教程:使用 ASP.NET Core 创建 Web API 您所在的位置:网站首页 visual studio code新建一个HTML页面模板 教程:使用 ASP.NET Core 创建 Web API

教程:使用 ASP.NET Core 创建 Web API

2024-01-15 06:23| 来源: 网络整理| 查看: 265

教程:使用 ASP.NET Core 创建 Web API 项目 01/03/2024

注意

此版本不是本文的最新版本。 对于当前版本,请参阅此文的 .NET 8 版本。

作者:Rick Anderson 和 Kirk Larkin

本教程介绍生成使用数据库的基于控制器的 Web API 的基础知识。 在 ASP.NET Core 中创建 API 的另一种方法是创建最小 API。 有关在最小 API 和基于控制器的 API 之间进行选择的帮助,请参阅 API 概述。 有关创建最小 API 的教程,请参阅教程:使用 ASP.NET Core 创建最小 API。

概述

本教程将创建以下 API:

API 描述 请求正文 响应正文 GET /api/todoitems 获取所有待办事项 None 待办事项的数组 GET /api/todoitems/{id} 按 ID 获取项 None 待办事项 POST /api/todoitems 添加新项 待办事项 待办事项 PUT /api/todoitems/{id} 更新现有项 待办事项 None DELETE /api/todoitems/{id}     删除项 None None

下图显示了应用的设计。

先决条件 Visual Studio Visual Studio Code Visual Studio for Mac

Visual Studio 2022 预览版与“ASP.NET 和 Web 开发”工作负载。

Visual Studio Code 用于 Visual Studio Code 的 C#(最新版本) .NET 8.0 SDK

Visual Studio Code 说明使用用于 ASP.NET Core 的 .NET CLI 开发功能,如项目创建。 可在(macOS、Linux 或 Windows)上或在任何代码编辑器中遵循这些说明。 如果使用 Visual Studio Code 以外的其他内容,则可能需要进行少量更改。

Visual Studio 2022 for Mac(最新版本)

在 Visual Studio 2022 for Mac 中,选择“工具”>“首选项...”>“预览功能”,并启用“如果已安装则使用 .NET 8 SDK(需要重启)”。

重要

Microsoft 已宣布停用 Visual Studio for Mac。 从 2024 年 8 月 31 日起,将不再支持 Visual Studio for Mac。 替代方案包括:

带有 C# 开发工具包 和相关扩展(如 .NET MAUI 和 Unity)的 Visual Studio Code。 在 Mac 虚拟机中的 Windows 上运行的 Visual Studio IDE。 在云虚拟机中的 Windows 上运行的 Visual Studio IDE。

有关详细信息,请参阅 Visual Studio for Mac 停用公告。

创建 Web 项目 Visual Studio Visual Studio Code Visual Studio for Mac 从“文件”菜单中选择“新建”>“项目” 。 在搜索框中输入“Web API”。 选择“ASP.NET Core Web API”模板,然后选择“下一步”。 在“配置新项目”对话框中,将项目命名为“TodoApi”,然后选择“下一步”。 在“其他信息”对话框中: 确认“框架”为“.NET 8.0 (长期支持)”。 确认已选中“使用控制器(取消选中以使用最小 API)”。 确认已选中“启用 OpenAPI 支持”复选框。 选择“创建”。 添加 NuGet 包

必须添加 NuGet 包以支持本教程中使用的数据库。

在“工具”菜单中,选择“NuGet 包管理器”>“管理解决方案的 NuGet 包”。 选择“浏览”选项卡。 在搜索框中输入“Microsoft.EntityFrameworkCore.InMemory”,然后选择 Microsoft.EntityFrameworkCore.InMemory。 选中右窗格中的“项目”复选框,然后选择“安装” 。

打开集成终端。

将目录 (cd) 更改为包含项目文件夹的文件夹。

运行以下命令:

dotnet new webapi --use-controllers -o TodoApi cd TodoApi dotnet add package Microsoft.EntityFrameworkCore.InMemory code -r ../TodoApi

这些命令会:

创建新的 Web API 项目,并在 Visual Studio Code 中打开它。 添加下一部分所需的 NuGet 包。 在 Visual Studio Code 的当前实例中打开 TodoApi 文件夹。

Visual Studio Code 可能会显示一个对话框,询问:“你是否信任此文件夹中的文件作者?”

如果你信任父文件夹中的所有文件,请选择“信任父文件夹中所有文件的作者”。 选择“是,我信任所有作者”,因为项目文件夹包含 .NET 生成的文件。 当 Visual Studio Code 请求你添加资产来生成和调试项目时,请选择“是”。 如果 Visual Studio Code 不提供添加生成和调试资产的功能,请选择“视图”>“命令面板”,然后在搜索框中输入“.NET”。 从命令列表中选择 .NET: Generate Assets for Build and Debug 命令。

Visual Studio Code 添加了一个包含生成的 launch.json 和 tasks.json 文件的 .vscode 文件夹。

在 Visual Studio for Mac 2022 中,选择“文件”>“新建项目...”。

在“为新项目选择一个模板”对话框中:

选择“Web 和控制台”>“应用”>“API”。 选择“继续”。

在“配置新 API”对话框中,做出以下选择:

确认“目标框架”是“.NET 8.0”。 确认已选中“启用 OpenAPI 支持”复选框。 确认已选中“使用控制器”复选框。 选择“创建”。

输入以下内容:

项目名称:TodoApi 解决方案名称:TodoApi 选择“创建”。 添加 NuGet 包 在 Visual Studio for Mac 2022 工具栏中,选择“项目”>“管理 NuGet 包...”。 在搜索框中,输入 Microsoft.EntityFrameworkCore.InMemory。 在结果窗口中,选中 Microsoft.EntityFrameworkCore.InMemory。 选择“添加包” 在“选择项目”窗口中,选择“确定”。 在“许可协议”窗口中,选择“同意”。

说明

有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。

测试项目

项目模板创建了一个支持 Swagger 的 WeatherForecast API。

Visual Studio Visual Studio Code Visual Studio for Mac

按 Ctrl+F5 以在不使用调试程序的情况下运行。

如果尚未将项目配置为使用 SSL,Visual Studio 显示以下对话:

如果信任 IIS Express SSL 证书,请选择“是”。

将显示以下对话框:

如果你同意信任开发证书,请选择“是”。

有关信任 Firefox 浏览器的信息,请参阅 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE 证书错误。

Visual Studio 将启动默认浏览器并导航到 https://localhost:/swagger/index.html,其中 是在创建项目时设置的一个随机选择的端口号。

通过运行以下命令来信任 HTTPS 开发证书:

dotnet dev-certs https --trust

上述命令在 Linux 上无效。 有关信任证书的详细信息,请参阅 Linux 发行版的文档。

如果证书以前不受信任,上述命令显示以下对话:

如果你同意信任开发证书,请选择“是”。

有关详细信息,请参阅信任 ASP.NET Core HTTPS 开发证书。

有关信任 Firefox 浏览器的信息,请参阅 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE 证书错误。

运行应用:

运行以下命令,在 https 配置文件上启动应用:

dotnet run --launch-profile https

输出会显示类似于以下内容的消息,表示应用正在运行且正在等待请求:

... info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:{port} ...

Ctrl+单击输出中的 HTTPS URL 以在浏览器中测试 Web 应用。

默认浏览器会启动到 https://localhost:/swagger/index.html,其中 是输出中显示的随机选择的端口号。 https://localhost: 没有终结点,因此浏览器返回 HTTP 404 未找到。 将 /swagger 附加到 URL https://localhost:/swagger。

按照以下说明测试 Web 应用后,在集成终端中按 Ctrl+C 来将其关闭。

选择“调试”>“开始调试”以启动应用。 Visual Studio for Mac 将启动一个浏览器并导航到 https://localhost:/swagger/index.html,其中 是在创建项目时设置的一个随机选择的端口号。

随即显示 Swagger 页面 /swagger/index.html。 选择 GET >“试用”>“执行” 。 页面将显示:

用于测试 WeatherForecast API 的 Curl 命令。 用于测试 WeatherForecast API 的 URL。 响应代码、正文和标头。 包含媒体类型、示例值和架构的下拉列表框。

如果 Swagger 页面未显示,请参阅此 GitHub 问题。

Swagger 用于为 Web API 生成有用的文档和帮助页面。 本教程使用 Swagger 测试应用。 有关 Swagger 的详细信息,请参阅包含 Swagger / OpenAPI 的 ASP.NET Core Web API 文档。

将请求 URL 复制粘贴到浏览器中:https://localhost:/weatherforecast

返回类似于以下示例的 JSON:

[ { "date": "2019-07-16T19:04:05.7257911-06:00", "temperatureC": 52, "temperatureF": 125, "summary": "Mild" }, { "date": "2019-07-17T19:04:05.7258461-06:00", "temperatureC": 36, "temperatureF": 96, "summary": "Warm" }, { "date": "2019-07-18T19:04:05.7258467-06:00", "temperatureC": 39, "temperatureF": 102, "summary": "Cool" }, { "date": "2019-07-19T19:04:05.7258471-06:00", "temperatureC": 10, "temperatureF": 49, "summary": "Bracing" }, { "date": "2019-07-20T19:04:05.7258474-06:00", "temperatureC": -1, "temperatureF": 31, "summary": "Chilly" } ] 添加模型类

模型是一组表示应用管理的数据的类。 此应用的模型是 TodoItem 类。

Visual Studio Visual Studio Code Visual Studio for Mac 在“解决方案资源管理器”中,右键单击项目。 选择“添加”>“新建文件夹”。 将该文件夹命名为 Models注册一个免费试用帐户。 右键单击 Models 文件夹,然后选择“添加”>“类”。 将类命名为 TodoItem,然后选择“添加”。 将模板代码替换为以下内容: 添加名为 Models 的文件夹。 使用以下代码将 TodoItem.cs 文件添加到 Models 文件夹:

按 Control 并单击“TodoAPI”项目,然后选择“添加”>“新建文件夹”。 将该文件夹命名为 Models注册一个免费试用帐户。

按 Control 并单击 Models 文件夹,然后选择“添加”>“新建类...”>“常规”>“空类”。

将类命名为“TodoItem”,然后选择“创建”。

将模板代码替换为以下内容:

namespace TodoApi.Models; public class TodoItem { public long Id { get; set; } public string? Name { get; set; } public bool IsComplete { get; set; } }

Id 属性用作关系数据库中的唯一键。

模型类可位于项目的任意位置,但按照惯例会使用 Models 文件夹。

添加数据库上下文

数据库上下文是为数据模型协调 Entity Framework 功能的主类。 此类由 Microsoft.EntityFrameworkCore.DbContext 类派生而来。

Visual Studio Visual Studio Code / Visual Studio for Mac 右键单击 Models 文件夹,然后选择“添加”>“类”。 将类命名为 TodoContext,然后单击“添加”。 将 TodoContext.cs 文件添加到 Models 文件夹中。

输入以下代码:

using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions options) : base(options) { } public DbSet TodoItems { get; set; } = null!; } 注册数据库上下文

在 ASP.NET Core 中,服务(如数据库上下文)必须向依赖关系注入 (DI) 容器进行注册。 该容器向控制器提供服务。

使用以下突出显示的代码更新 Program.cs:

using Microsoft.EntityFrameworkCore; using TodoApi.Models; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddDbContext(opt => opt.UseInMemoryDatabase("TodoList")); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();

前面的代码:

添加 using 指令。 将数据库上下文添加到 DI 容器。 指定数据库上下文将使用内存中数据库。 构建控制器 Visual Studio Visual Studio Code / Visual Studio for Mac

右键单击 Controllers 文件夹。

选择“添加”>“新建构建项”。

选择“其操作使用实体框架的 API 控制器”,然后选择“添加” 。

在“添加其操作使用实体框架的 API 控制器”对话框中:

在“模型类”中选择“TodoItem (TodoApi.Models)” 。 在“数据上下文类”中选择“TodoContext (TodoAPI.Models)” 。 选择“添加”。

如果基架操作失败,请选择“添加”以第二次尝试使用基架。

请确保目前所有更改均已保存。

按 Control 并单击“TodoAPI”项目,然后选择“在终端中打开”。 终端将在 TodoAPI 项目文件夹中打开。 运行以下命令: dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design dotnet add package Microsoft.EntityFrameworkCore.Design dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet add package Microsoft.EntityFrameworkCore.Tools dotnet tool uninstall -g dotnet-aspnet-codegenerator dotnet tool install -g dotnet-aspnet-codegenerator dotnet tool update -g dotnet-aspnet-codegenerator

前面的命令:

添加构建所需的 NuGet 包。 卸载任何可能的早期版本后,安装基架引擎 (dotnet-aspnet-codegenerator)。

注意

默认情况下,要安装的 .NET 二进制文件的体系结构表示当前运行的 OS 体系结构。 若要指定不同的 OS 体系结构,请参阅 dotnet tool install, --arch option。 有关详细信息,请参阅 GitHub 问题 dotnet/AspNetCore.Docs #29262。

生成项目。

运行以下命令:

dotnet aspnet-codegenerator controller -name TodoItemsController -async -api -m TodoItem -dc TodoContext -outDir Controllers

上述命令为 TodoItemsController 创建基架。

生成的代码:

使用 [ApiController] 属性标记类。 此属性指示控制器响应 Web API 请求。 有关该属性启用的特定行为的信息,请参阅使用 ASP.NET Core 创建 Web API。 使用 DI 将数据库上下文 (TodoContext) 注入到控制器中。 数据库上下文将在控制器中的每个 CRUD 方法中使用。

ASP.NET Core 模板:

具有视图的控制器在路由模板中包含 [action]。 API 控制器不在路由模板中包含 [action]。

[action] 令牌不在路由模板中时,终结点中不包含 action 名称(方法名称)。 也就是说,不会在匹配的路由中使用操作的关联方法名称。

更新 PostTodoItem create 方法

更新 PostTodoItem 中的 return 语句,以使用 nameof 运算符:

[HttpPost] public async Task PostTodoItem(TodoItem todoItem) { _context.TodoItems.Add(todoItem); await _context.SaveChangesAsync(); // return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem); return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem); }

上述代码是 HTTP POST 方法,如 [HttpPost] 属性所指示。 此方法从 HTTP 请求正文获取 TodoItem 的值。

有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

CreatedAtAction 方法:

如果成功,将返回 HTTP 201 状态代码。 HTTP 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。 向响应添加位置标头。 Location 标头指定新建的待办事项的 URI。 有关详细信息,请参阅创建的 10.2.2 201。 引用 GetTodoItem 操作以创建 Location 标头的 URI。 C# nameof 关键字用于避免在 CreatedAtAction 调用中硬编码操作名称。

测试 PostTodoItem

按 Ctrl+F5 运行应用。

在 Swagger 浏览器窗口中,选择“POST /api/TodoItems”,然后选择“试用”。

在“请求正文”输入窗口中,更新 JSON。 例如,

{ "name": "walk dog", "isComplete": true }

选择“执行”

测试位置标头 URI

在上述 POST 中,Swagger UI 在“响应标头”下显示了位置标头。 例如 location: https://localhost:7260/api/TodoItems/1。 位置标头显示创建资源的 URI。

测试位置标头:

在 Swagger 浏览器窗口中,选择“GET /api/TodoItems/{id}”,然后选择“试用”。

在 id 输入框中输入 1,然后选择“执行”。

检查 GET 方法

实现了两个 GET 终结点:

GET /api/todoitems GET /api/todoitems/{id}

上一节展示了 /api/todoitems/{id} 路由的示例。

按照 POST 说明添加另一待办事项,然后使用 Swagger 测试 /api/todoitems 路由。

此应用使用内存中数据库。 如果应用已停止并启动,则前面的 GET 请求将不会返回任何数据。 如果未返回任何数据,将数据 POST 到应用。

路由和 URL 路径

[HttpGet] 属性表示响应 HTTP GET 请求的方法。 每个方法的 URL 路径构造如下所示:

在控制器的 Route 属性中以模板字符串开头:

[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase

将 [controller] 替换为控制器的名称,按照惯例,在控制器类名称中去掉“Controller”后缀。 对于此示例,控制器类名称为“TodoItems”控制器,因此控制器名称为“TodoItems”。 ASP.NET Core 路由不区分大小写。

如果 [HttpGet] 属性具有路由模板(例如 [HttpGet("products")]),则将它追加到路径。 此示例不使用模板。 有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

在下面的 GetTodoItem 方法中,"{id}" 是待办事项的唯一标识符的占位符变量。 调用 GetTodoItem 时,URL 中 "{id}" 的值会在 id 参数中提供给方法。

[HttpGet("{id}")] public async Task GetTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } return todoItem; } 返回值

GetTodoItems 和 GetTodoItem 方法的返回类型是 ActionResult 类型。 ASP.NET Core 自动将对象序列化为 JSON,并将 JSON 写入响应消息的正文中。 此返回类型的响应代码为 200 OK(假设没有未处理的异常)。 未经处理的异常将转换为 5xx 错误。

ActionResult 返回类型可以表示大范围的 HTTP 状态代码。 例如,GetTodoItem 可以返回两个不同的状态值:

如果没有任何项与请求的 ID 匹配,该方法将返回 404 状态NotFound错误代码。 否则,此方法将返回具有 JSON 响应正文的 200。 返回 item 则产生 HTTP 200 响应。 PutTodoItem 方法

检查 PutTodoItem 方法:

[HttpPut("{id}")] public async Task PutTodoItem(long id, TodoItem todoItem) { if (id != todoItem.Id) { return BadRequest(); } _context.Entry(todoItem).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!TodoItemExists(id)) { return NotFound(); } else { throw; } } return NoContent(); }

PutTodoItem 与 PostTodoItem 类似,但使用的是 HTTP PUT。 响应是 204(无内容)。 根据 HTTP 规范,PUT 请求需要客户端发送整个更新的实体,而不仅仅是更改。 若要支持部分更新,请使用 HTTP PATCH。

测试 PutTodoItem 方法

本示例使用内存内、数据库,每次启动应用时都必须对其进行初始化。 在进行 PUT 调用之前,数据库中必须有一个项。 调用 GET,以确保在调用 PUT 之前数据库中存在项。

使用 Swagger UI,使用 PUT 按钮更新 Id = 1 的 TodoItem 并将其名称设置为 "feed fish"。 请注意,响应为 HTTP 204 No Content。

DeleteTodoItem 方法

检查 DeleteTodoItem 方法:

[HttpDelete("{id}")] public async Task DeleteTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } _context.TodoItems.Remove(todoItem); await _context.SaveChangesAsync(); return NoContent(); } 测试 DeleteTodoItem 方法

使用 Swagger UI 删除 Id = 1 的 TodoItem。 请注意,响应为 HTTP 204 No Content。

使用其他工具进行测试

还有许多其他工具可用于测试 Web API,例如:

Visual Studio 终结点资源管理器和 .http 文件 http-repl Postman curl。 Swagger 使用 curl 并显示它提交的 curl 命令。 Fiddler

有关详细信息,请参阅:

最小 API 教程:使用 .http 文件和终结点资源管理器进行测试 使用 Postman 测试 API 使用 http-repl 安装并测试 API

防止过度发布

目前,示例应用公开了整个 TodoItem 对象。 生产应用通常使用模型的子集来限制输入和返回的数据。 这背后有多种原因,但安全性是主要原因。 模型的子集通常称为数据传输对象 (DTO)、输入模型或视图模型。 本教程使用了 DTO。

DTO 可用于:

防止过度发布。 隐藏客户端不应查看的属性。 省略一些属性以缩减有效负载大小。 平展包含嵌套对象的对象图。 对客户端而言,平展的对象图可能更方便。

若要演示 DTO 方法,请更新 TodoItem 类,使其包含机密字段:

namespace TodoApi.Models { public class TodoItem { public long Id { get; set; } public string? Name { get; set; } public bool IsComplete { get; set; } public string? Secret { get; set; } } }

此应用需要隐藏机密字段,但管理应用可以选择公开它。

确保可以发布和获取机密字段。

创建 DTO 模型:

namespace TodoApi.Models; public class TodoItemDTO { public long Id { get; set; } public string? Name { get; set; } public bool IsComplete { get; set; } }

更新 TodoItemsController 以使用 TodoItemDTO:

using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TodoApi.Models; namespace TodoApi.Controllers; [Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase { private readonly TodoContext _context; public TodoItemsController(TodoContext context) { _context = context; } // GET: api/TodoItems [HttpGet] public async Task GetTodoItems() { return await _context.TodoItems .Select(x => ItemToDTO(x)) .ToListAsync(); } // GET: api/TodoItems/5 // [HttpGet("{id}")] public async Task GetTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } return ItemToDTO(todoItem); } // // PUT: api/TodoItems/5 // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 // [HttpPut("{id}")] public async Task PutTodoItem(long id, TodoItemDTO todoDTO) { if (id != todoDTO.Id) { return BadRequest(); } var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } todoItem.Name = todoDTO.Name; todoItem.IsComplete = todoDTO.IsComplete; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) when (!TodoItemExists(id)) { return NotFound(); } return NoContent(); } // // POST: api/TodoItems // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 // [HttpPost] public async Task PostTodoItem(TodoItemDTO todoDTO) { var todoItem = new TodoItem { IsComplete = todoDTO.IsComplete, Name = todoDTO.Name }; _context.TodoItems.Add(todoItem); await _context.SaveChangesAsync(); return CreatedAtAction( nameof(GetTodoItem), new { id = todoItem.Id }, ItemToDTO(todoItem)); } // // DELETE: api/TodoItems/5 [HttpDelete("{id}")] public async Task DeleteTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } _context.TodoItems.Remove(todoItem); await _context.SaveChangesAsync(); return NoContent(); } private bool TodoItemExists(long id) { return _context.TodoItems.Any(e => e.Id == id); } private static TodoItemDTO ItemToDTO(TodoItem todoItem) => new TodoItemDTO { Id = todoItem.Id, Name = todoItem.Name, IsComplete = todoItem.IsComplete }; }

确保无法发布或获取机密字段。

使用 JavaScript 调用 Web API

请参阅教程:使用 JavaScript 调用 ASP.NET Core Web API。

Web API 视频系列

请参阅视频:初学者系列:Web API。

可靠的 Web 应用模式

请观看适用于 .NET 的可靠 Web 应用模式YouTube 视频和文章,了解如何创建新式、可靠、高性能、可测试、经济高效且可缩放的 ASP.NET Core 应用,无论是从头开始创建还是重构现有应用。

向 Web API 添加身份验证支持

ASP.NET Core Identity 将用户界面 (UI) 登录功能添加到 ASP.NET Core Web 应用。 若要保护 Web API 和 SPA,请使用以下项之一:

Microsoft Entra ID Azure Active Directory B2C (Azure AD B2C) Duende Identity Server

Duende Identity Server 是适用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 框架。 Duende Identity Server 支持以下安全功能:

身份验证即服务 (AaaS) 跨多个应用程序类型的单一登录/注销 (SSO) API 的访问控制 Federation Gateway

重要事项

Duende Software 可能会要求你为 Duende Identity Server 的生产使用支付许可证费用。 有关详细信息,请参阅从 ASP.NET Core 5.0 迁移到 6.0。

有关详细信息,请参阅 Duende Identity Server 文档(Duende Software 网站)。

发布到 Azure

有关部署到 Azure 的信息,请参阅快速入门:部署 ASP.NET Web 应用。

其他资源

查看或下载本教程的示例代码。 请参阅如何下载。

有关更多信息,请参见以下资源:

使用 ASP.NET Core 创建 Web API 教程:使用 ASP.NET Core 创建最小 API 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档 RazorASP.NET Core 中的 Pages 和 Entity Framework Core - 第 1 个教程(共 8 个) 在 ASP.NET Core 中路由到控制器操作 ASP.NET Core Web API 中控制器操作的返回类型 将 ASP.NET Core 应用部署到 Azure 应用服务 托管和部署 ASP.NET Core 使用 ASP.NET Core 创建 Web API

本教程介绍生成使用数据库的基于控制器的 Web API 的基础知识。 在 ASP.NET Core 中创建 API 的另一种方法是创建最小 API。 有关在最小 API 和基于控制器的 API 之间进行选择的帮助,请参阅 API 概述。 有关创建最小 API 的教程,请参阅教程:使用 ASP.NET Core 创建最小 API。

概述

本教程将创建以下 API:

API 描述 请求正文 响应正文 GET /api/todoitems 获取所有待办事项 None 待办事项的数组 GET /api/todoitems/{id} 按 ID 获取项 None 待办事项 POST /api/todoitems 添加新项 待办事项 待办事项 PUT /api/todoitems/{id} 更新现有项 待办事项 None DELETE /api/todoitems/{id}     删除项 None None

下图显示了应用的设计。

先决条件 Visual Studio Visual Studio Code Visual Studio for Mac

带有 ASP.NET 和 Web 开发工作负载的 Visual Studio 2022。

Visual Studio Code 用于 Visual Studio Code 的 C#(最新版本) .NET 7.0 SDK

Visual Studio Code 说明使用用于 ASP.NET Core 的 .NET CLI 开发功能,如项目创建。 可在(macOS、Linux 或 Windows)上或在任何代码编辑器中遵循这些说明。 如果使用 Visual Studio Code 以外的其他内容,则可能需要进行少量更改。

Visual Studio 2022 for Mac

重要

Microsoft 已宣布停用 Visual Studio for Mac。 从 2024 年 8 月 31 日起,将不再支持 Visual Studio for Mac。 替代方案包括:

带有 C# 开发工具包 和相关扩展(如 .NET MAUI 和 Unity)的 Visual Studio Code。 在 Mac 虚拟机中的 Windows 上运行的 Visual Studio IDE。 在云虚拟机中的 Windows 上运行的 Visual Studio IDE。

有关详细信息,请参阅 Visual Studio for Mac 停用公告。

创建 Web 项目 Visual Studio Visual Studio Code Visual Studio for Mac 从“文件”菜单中选择“新建”>“项目” 。 在搜索框中输入“Web API”。 选择“ASP.NET Core Web API”模板,然后选择“下一步”。 在“配置新项目”对话框中,将项目命名为“TodoApi”,然后选择“下一步”。 在“其他信息”对话框中: 确认“框架”是“.NET 7.0”(或更高版本)。 确认已选中“使用控制器(取消选中以使用最小 API)”。 选择“创建”。

打开集成终端。

将目录 (cd) 更改为包含项目文件夹的文件夹。

运行以下命令:

dotnet new webapi -o TodoApi -f net7.0 cd TodoApi dotnet add package Microsoft.EntityFrameworkCore.InMemory -v 7.0.0 code -r ../TodoApi

这些命令会:

创建面向 .NET 7.0 的新 Web API 项目,并在 Visual Studio Code 中打开该项目。 添加下一部分所需的 NuGet 包。 在 Visual Studio Code 的当前实例中打开 TodoApi 文件夹。

Visual Studio Code 可能会显示一个对话框,询问:“你是否信任此文件夹中的文件作者?”

如果你信任父文件夹中的所有文件,请选择“信任父文件夹中所有文件的作者”。 选择“是,我信任所有作者”,因为项目文件夹包含 .NET 生成的文件。 当 Visual Studio Code 请求你添加资产来生成和调试项目时,请选择“是”。 如果 Visual Studio Code 不提供添加生成和调试资产的功能,请选择“视图”>“命令面板”,然后在搜索框中输入“.NET”。 从命令列表中选择 .NET: Generate Assets for Build and Debug 命令。

Visual Studio Code 添加了一个包含生成的 launch.json 和 tasks.json 文件的 .vscode 文件夹。

在 Visual Studio for Mac 2022 中,选择“文件”>“新建项目...”。

在“为新项目选择一个模板”对话框中:

选择“Web 和控制台”>“应用”>“API”。 选择“继续”。

在“配置新 API”对话框中,做出以下选择:

确认“目标框架”是“.NET 7.0”(或更高版本)。 确认已选中“使用控制器(取消选中以使用最小 API)”复选框。 确认已选中“启用 OpenAPI 支持”复选框。 选择“继续”。

输入以下内容:

项目名称:TodoApi 解决方案名称:TodoApi 选择“创建”。 添加 NuGet 包 在 Visual Studio for Mac 2022 工具栏中,选择“项目”>“管理 NuGet 包...” 在搜索框中,输入 Microsoft.EntityFrameworkCore.InMemory。 在结果窗口中,选中 Microsoft.EntityFrameworkCore.InMemory。 选择“添加包” 在“选择项目”窗口中,选择“确定” 在“许可协议”窗口中,选择“同意”

注意

有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。

测试项目

项目模板创建了一个支持 Swagger 的 WeatherForecast API。

Visual Studio Visual Studio Code Visual Studio for Mac

按 Ctrl+F5 以在不使用调试程序的情况下运行。

如果尚未将项目配置为使用 SSL,Visual Studio 显示以下对话:

如果信任 IIS Express SSL 证书,请选择“是”。

将显示以下对话框:

如果你同意信任开发证书,请选择“是”。

有关信任 Firefox 浏览器的信息,请参阅 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE 证书错误。

Visual Studio 启动默认浏览器并导航到 https://localhost:/swagger/index.html,其中 是随机选择的端口号。

通过运行以下命令来信任 HTTPS 开发证书:

dotnet dev-certs https --trust

上述命令在 Linux 上无效。 有关信任证书的详细信息,请参阅 Linux 发行版的文档。

如果证书以前不受信任,上述命令显示以下对话:

如果你同意信任开发证书,请选择“是”。

有关详细信息,请参阅信任 ASP.NET Core HTTPS 开发证书。

有关信任 Firefox 浏览器的信息,请参阅 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE 证书错误。

运行应用:

运行以下命令,在 https 配置文件上启动应用:

dotnet run --launch-profile https

输出会显示类似于以下内容的消息,表示应用正在运行且正在等待请求:

... info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:{port} ...

Ctrl+单击输出中的 HTTPS URL 以在浏览器中测试 Web 应用。

默认浏览器会启动到 https://localhost:,其中 是输出中显示的随机选择的端口号。 https://localhost: 没有终结点,因此浏览器返回 HTTP 404 未找到。 将 /swagger 附加到 URL https://localhost:/swagger。

按照以下说明测试 Web 应用后,在集成终端中按 Ctrl+C 来将其关闭。

选择“调试”>“开始调试”以启动应用。 Visual Studio for Mac 会启动浏览器并导航到 https://localhost:,其中 是随机选择的端口号。 https://localhost: 没有终结点,因此浏览器返回 HTTP 404 Not Found。 将 /swagger 附加到 URL https://localhost:/swagger。

随即显示 Swagger 页面 /swagger/index.html。 选择 GET >“试用”>“执行” 。 页面将显示:

用于测试 WeatherForecast API 的 Curl 命令。 用于测试 WeatherForecast API 的 URL。 响应代码、正文和标头。 包含媒体类型、示例值和架构的下拉列表框。

如果 Swagger 页面未显示,请参阅此 GitHub 问题。

Swagger 用于为 Web API 生成有用的文档和帮助页面。 本教程重点介绍如何创建 Web API。 有关 Swagger 的详细信息,请参阅包含 Swagger / OpenAPI 的 ASP.NET Core Web API 文档。

将请求 URL 复制粘贴到浏览器中:https://localhost:/weatherforecast

返回类似于以下示例的 JSON:

[ { "date": "2019-07-16T19:04:05.7257911-06:00", "temperatureC": 52, "temperatureF": 125, "summary": "Mild" }, { "date": "2019-07-17T19:04:05.7258461-06:00", "temperatureC": 36, "temperatureF": 96, "summary": "Warm" }, { "date": "2019-07-18T19:04:05.7258467-06:00", "temperatureC": 39, "temperatureF": 102, "summary": "Cool" }, { "date": "2019-07-19T19:04:05.7258471-06:00", "temperatureC": 10, "temperatureF": 49, "summary": "Bracing" }, { "date": "2019-07-20T19:04:05.7258474-06:00", "temperatureC": -1, "temperatureF": 31, "summary": "Chilly" } ] 添加模型类

模型是一组表示应用管理的数据的类。 此应用的模型是 TodoItem 类。

Visual Studio Visual Studio Code Visual Studio for Mac 在“解决方案资源管理器”中,右键单击项目。 选择“添加”>“新建文件夹”。 将该文件夹命名为 Models注册一个免费试用帐户。 右键单击 Models 文件夹,然后选择“添加”>“类”。 将类命名为 TodoItem,然后选择“添加”。 将模板代码替换为以下内容: 添加名为 Models 的文件夹。 使用以下代码将 TodoItem.cs 文件添加到 Models 文件夹:

按 Control 并单击“TodoAPI”项目,然后选择“添加”>“新建文件夹”。 将该文件夹命名为 Models注册一个免费试用帐户。

按 Control 并单击 Models 文件夹,然后选择“添加”>“新建类...”>“常规”>“空类”。

将类命名为“TodoItem”,然后选择“创建”。

将模板代码替换为以下内容:

namespace TodoApi.Models; public class TodoItem { public long Id { get; set; } public string? Name { get; set; } public bool IsComplete { get; set; } }

Id 属性用作关系数据库中的唯一键。

模型类可位于项目的任意位置,但按照惯例会使用 Models 文件夹。

添加数据库上下文

数据库上下文是为数据模型协调 Entity Framework 功能的主类。 此类由 Microsoft.EntityFrameworkCore.DbContext 类派生而来。

Visual Studio Visual Studio Code / Visual Studio for Mac 添加 NuGet 包 在“工具”菜单中,选择“NuGet 包管理器”>“管理解决方案的 NuGet 包”。 选择“浏览”选项卡,然后在搜索框中输入“Microsoft.EntityFrameworkCore.InMemory” 。 在左窗格中,选择“Microsoft.EntityFrameworkCore.InMemory”。 选中右窗格中的“项目”复选框,然后选择“安装” 。 添加 TodoContext 数据库上下文 右键单击 Models 文件夹,然后选择“添加”>“类”。 将类命名为 TodoContext,然后单击“添加”。 将 TodoContext.cs 文件添加到 Models 文件夹中。

输入以下代码:

using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions options) : base(options) { } public DbSet TodoItems { get; set; } = null!; } 注册数据库上下文

在 ASP.NET Core 中,服务(如数据库上下文)必须向依赖关系注入 (DI) 容器进行注册。 该容器向控制器提供服务。

使用以下突出显示的代码更新 Program.cs:

using Microsoft.EntityFrameworkCore; using TodoApi.Models; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddDbContext(opt => opt.UseInMemoryDatabase("TodoList")); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();

前面的代码:

添加 using 指令。 将数据库上下文添加到 DI 容器。 指定数据库上下文将使用内存中数据库。 构建控制器 Visual Studio Visual Studio Code / Visual Studio for Mac

右键单击 Controllers 文件夹。

选择“添加”>“新建构建项”。

选择“其操作使用实体框架的 API 控制器”,然后选择“添加” 。

在“添加其操作使用实体框架的 API 控制器”对话框中:

在“模型类”中选择“TodoItem (TodoApi.Models)” 。 在“数据上下文类”中选择“TodoContext (TodoAPI.Models)” 。 选择“添加”。

如果基架操作失败,请选择“添加”以第二次尝试使用基架。

请确保目前所有更改均已保存。

按 Control 并单击“TodoAPI”项目,然后选择“在终端中打开”。 终端将在 TodoAPI 项目文件夹中打开。 运行以下命令: dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design -v 7.0.0 dotnet add package Microsoft.EntityFrameworkCore.Design -v 7.0.0 dotnet add package Microsoft.EntityFrameworkCore.SqlServer -v 7.0.0 dotnet add package Microsoft.EntityFrameworkCore.Tools -v 7.0.0 dotnet tool uninstall -g dotnet-aspnet-codegenerator dotnet tool install -g dotnet-aspnet-codegenerator dotnet tool update -g dotnet-aspnet-codegenerator

前面的命令:

添加构建所需的 NuGet 包。 卸载任何可能的早期版本后,安装基架引擎 (dotnet-aspnet-codegenerator)。

注意

默认情况下,要安装的 .NET 二进制文件的体系结构表示当前运行的 OS 体系结构。 若要指定不同的 OS 体系结构,请参阅 dotnet tool install, --arch option。 有关详细信息,请参阅 GitHub 问题 dotnet/AspNetCore.Docs #29262。

生成项目。

运行以下命令:

dotnet aspnet-codegenerator controller -name TodoItemsController -async -api -m TodoItem -dc TodoContext -outDir Controllers

上述命令为 TodoItemsController 创建基架。

生成的代码:

使用 [ApiController] 属性标记类。 此属性指示控制器响应 Web API 请求。 有关该属性启用的特定行为的信息,请参阅使用 ASP.NET Core 创建 Web API。 使用 DI 将数据库上下文 (TodoContext) 注入到控制器中。 数据库上下文将在控制器中的每个 CRUD 方法中使用。

ASP.NET Core 模板:

具有视图的控制器在路由模板中包含 [action]。 API 控制器不在路由模板中包含 [action]。

[action] 令牌不在路由模板中时,终结点中不包含 action 名称(方法名称)。 也就是说,不会在匹配的路由中使用操作的关联方法名称。

更新 PostTodoItem create 方法

更新 PostTodoItem 中的 return 语句,以使用 nameof 运算符:

[HttpPost] public async Task PostTodoItem(TodoItem todoItem) { _context.TodoItems.Add(todoItem); await _context.SaveChangesAsync(); // return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem); return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem); }

上述代码是 HTTP POST 方法,如 [HttpPost] 属性所指示。 此方法从 HTTP 请求正文获取 TodoItem 的值。

有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

CreatedAtAction 方法:

如果成功,将返回 HTTP 201 状态代码。 HTTP 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。 向响应添加位置标头。 Location 标头指定新建的待办事项的 URI。 有关详细信息,请参阅创建的 10.2.2 201。 引用 GetTodoItem 操作以创建 Location 标头的 URI。 C# nameof 关键字用于避免在 CreatedAtAction 调用中硬编码操作名称。

测试 PostTodoItem

按 Ctrl+F5 运行应用。

在 Swagger 浏览器窗口中,选择“POST /api/TodoItems”,然后选择“试用”。

在“请求正文”输入窗口中,更新 JSON。 例如,

{ "name": "walk dog", "isComplete": true }

选择“执行”

测试位置标头 URI

在上述 POST 中,Swagger UI 在“响应标头”下显示了位置标头。 例如 location: https://localhost:7260/api/TodoItems/1。 位置标头显示创建资源的 URI。

测试位置标头:

在 Swagger 浏览器窗口中,选择“GET /api/TodoItems/{id}”,然后选择“试用”。

在 id 输入框中输入 1,然后选择“执行”。

检查 GET 方法

实现了两个 GET 终结点:

GET /api/todoitems GET /api/todoitems/{id}

上一节展示了 /api/todoitems/{id} 路由的示例。

按照 POST 说明添加另一待办事项,然后使用 Swagger 测试 /api/todoitems 路由。

此应用使用内存中数据库。 如果应用已停止并启动,则前面的 GET 请求将不会返回任何数据。 如果未返回任何数据,将数据 POST 到应用。

路由和 URL 路径

[HttpGet] 属性表示响应 HTTP GET 请求的方法。 每个方法的 URL 路径构造如下所示:

在控制器的 Route 属性中以模板字符串开头:

[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase

将 [controller] 替换为控制器的名称,按照惯例,在控制器类名称中去掉“Controller”后缀。 对于此示例,控制器类名称为“TodoItems”控制器,因此控制器名称为“TodoItems”。 ASP.NET Core 路由不区分大小写。

如果 [HttpGet] 属性具有路由模板(例如 [HttpGet("products")]),则将它追加到路径。 此示例不使用模板。 有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

在下面的 GetTodoItem 方法中,"{id}" 是待办事项的唯一标识符的占位符变量。 调用 GetTodoItem 时,URL 中 "{id}" 的值会在 id 参数中提供给方法。

[HttpGet("{id}")] public async Task GetTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } return todoItem; } 返回值

GetTodoItems 和 GetTodoItem 方法的返回类型是 ActionResult 类型。 ASP.NET Core 自动将对象序列化为 JSON,并将 JSON 写入响应消息的正文中。 此返回类型的响应代码为 200 OK(假设没有未处理的异常)。 未经处理的异常将转换为 5xx 错误。

ActionResult 返回类型可以表示大范围的 HTTP 状态代码。 例如,GetTodoItem 可以返回两个不同的状态值:

如果没有任何项与请求的 ID 匹配,该方法将返回 404 状态NotFound错误代码。 否则,此方法将返回具有 JSON 响应正文的 200。 返回 item 则产生 HTTP 200 响应。 PutTodoItem 方法

检查 PutTodoItem 方法:

[HttpPut("{id}")] public async Task PutTodoItem(long id, TodoItem todoItem) { if (id != todoItem.Id) { return BadRequest(); } _context.Entry(todoItem).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!TodoItemExists(id)) { return NotFound(); } else { throw; } } return NoContent(); }

PutTodoItem 与 PostTodoItem 类似,但使用的是 HTTP PUT。 响应是 204(无内容)。 根据 HTTP 规范,PUT 请求需要客户端发送整个更新的实体,而不仅仅是更改。 若要支持部分更新,请使用 HTTP PATCH。

测试 PutTodoItem 方法

本示例使用内存内、数据库,每次启动应用时都必须对其进行初始化。 在进行 PUT 调用之前,数据库中必须有一个项。 调用 GET,以确保在调用 PUT 之前数据库中存在项。

使用 Swagger UI,使用 PUT 按钮更新 Id = 1 的 TodoItem 并将其名称设置为 "feed fish"。 请注意,响应为 HTTP 204 No Content。

DeleteTodoItem 方法

检查 DeleteTodoItem 方法:

[HttpDelete("{id}")] public async Task DeleteTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } _context.TodoItems.Remove(todoItem); await _context.SaveChangesAsync(); return NoContent(); } 测试 DeleteTodoItem 方法

使用 Swagger UI 删除 Id = 1 的 TodoItem。 请注意,响应为 HTTP 204 No Content。

使用 http-repl、Postman 或 curl 进行测试

http-repl、Postman 和 curl 通常用于测试 API。 Swagger 使用 curl 并显示它提交的 curl 命令。

有关这些工具的说明,请参阅以下链接:

使用 Postman 测试 API 使用 http-repl 安装并测试 API

有关 http-repl 的详细信息,请参阅使用 HttpRepl 测试 Web API。

防止过度发布

目前,示例应用公开了整个 TodoItem 对象。 生产应用通常使用模型的子集来限制输入和返回的数据。 这背后有多种原因,但安全性是主要原因。 模型的子集通常称为数据传输对象 (DTO)、输入模型或视图模型。 本教程使用了 DTO。

DTO 可用于:

防止过度发布。 隐藏客户端不应查看的属性。 省略一些属性以缩减有效负载大小。 平展包含嵌套对象的对象图。 对客户端而言,平展的对象图可能更方便。

若要演示 DTO 方法,请更新 TodoItem 类,使其包含机密字段:

namespace TodoApi.Models { public class TodoItem { public long Id { get; set; } public string? Name { get; set; } public bool IsComplete { get; set; } public string? Secret { get; set; } } }

此应用需要隐藏机密字段,但管理应用可以选择公开它。

确保可以发布和获取机密字段。

创建 DTO 模型:

namespace TodoApi.Models; public class TodoItemDTO { public long Id { get; set; } public string? Name { get; set; } public bool IsComplete { get; set; } }

更新 TodoItemsController 以使用 TodoItemDTO:

using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TodoApi.Models; namespace TodoApi.Controllers; [Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase { private readonly TodoContext _context; public TodoItemsController(TodoContext context) { _context = context; } // GET: api/TodoItems [HttpGet] public async Task GetTodoItems() { return await _context.TodoItems .Select(x => ItemToDTO(x)) .ToListAsync(); } // GET: api/TodoItems/5 // [HttpGet("{id}")] public async Task GetTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } return ItemToDTO(todoItem); } // // PUT: api/TodoItems/5 // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 // [HttpPut("{id}")] public async Task PutTodoItem(long id, TodoItemDTO todoDTO) { if (id != todoDTO.Id) { return BadRequest(); } var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } todoItem.Name = todoDTO.Name; todoItem.IsComplete = todoDTO.IsComplete; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) when (!TodoItemExists(id)) { return NotFound(); } return NoContent(); } // // POST: api/TodoItems // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 // [HttpPost] public async Task PostTodoItem(TodoItemDTO todoDTO) { var todoItem = new TodoItem { IsComplete = todoDTO.IsComplete, Name = todoDTO.Name }; _context.TodoItems.Add(todoItem); await _context.SaveChangesAsync(); return CreatedAtAction( nameof(GetTodoItem), new { id = todoItem.Id }, ItemToDTO(todoItem)); } // // DELETE: api/TodoItems/5 [HttpDelete("{id}")] public async Task DeleteTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } _context.TodoItems.Remove(todoItem); await _context.SaveChangesAsync(); return NoContent(); } private bool TodoItemExists(long id) { return _context.TodoItems.Any(e => e.Id == id); } private static TodoItemDTO ItemToDTO(TodoItem todoItem) => new TodoItemDTO { Id = todoItem.Id, Name = todoItem.Name, IsComplete = todoItem.IsComplete }; }

确保无法发布或获取机密字段。

使用 JavaScript 调用 Web API

请参阅教程:使用 JavaScript 调用 ASP.NET Core Web API。

Web API 视频系列

请参阅视频:初学者系列:Web API。

可靠的 Web 应用模式

请观看适用于 .NET 的可靠 Web 应用模式YouTube 视频和文章,了解如何创建新式、可靠、高性能、可测试、经济高效且可缩放的 ASP.NET Core 应用,无论是从头开始创建还是重构现有应用。

向 Web API 添加身份验证支持

ASP.NET Core Identity 将用户界面 (UI) 登录功能添加到 ASP.NET Core Web 应用。 若要保护 Web API 和 SPA,请使用以下项之一:

Microsoft Entra ID Azure Active Directory B2C (Azure AD B2C) Duende Identity Server

Duende Identity Server 是适用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 框架。 Duende Identity Server 支持以下安全功能:

身份验证即服务 (AaaS) 跨多个应用程序类型的单一登录/注销 (SSO) API 的访问控制 Federation Gateway

重要事项

Duende Software 可能会要求你为 Duende Identity Server 的生产使用支付许可证费用。 有关详细信息,请参阅从 ASP.NET Core 5.0 迁移到 6.0。

有关详细信息,请参阅 Duende Identity Server 文档(Duende Software 网站)。

发布到 Azure

有关部署到 Azure 的信息,请参阅快速入门:部署 ASP.NET Web 应用。

其他资源

查看或下载本教程的示例代码。 请参阅如何下载。

有关更多信息,请参见以下资源:

使用 ASP.NET Core 创建 Web API 教程:使用 ASP.NET Core 创建最小 API 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档 RazorASP.NET Core 中的 Pages 和 Entity Framework Core - 第 1 个教程(共 8 个) 在 ASP.NET Core 中路由到控制器操作 ASP.NET Core Web API 中控制器操作的返回类型 将 ASP.NET Core 应用部署到 Azure 应用服务 托管和部署 ASP.NET Core 使用 ASP.NET Core 创建 Web API

本教程介绍生成使用数据库的基于控制器的 Web API 的基础知识。 在 ASP.NET Core 中创建 API 的另一种方法是创建最小 API。 有关在最小 API 和基于控制器的 API 之间进行选择的帮助,请参阅 API 概述。 有关创建最小 API 的教程,请参阅教程:使用 ASP.NET Core 创建最小 API。

在本教程中,你将了解:

创建 Web API 项目。 添加模型类和数据库上下文。 使用 CRUD 方法构建控制器。 配置路由、URL 路径和返回值。 使用 http-repl 调用 Web API。

在结束时,你会获得可以管理存储在数据库中的“待办事项”的 Web API。

概述

本教程将创建以下 API:

API 描述 请求正文 响应正文 GET /api/todoitems 获取所有待办事项 None 待办事项的数组 GET /api/todoitems/{id} 按 ID 获取项 None 待办事项 POST /api/todoitems 添加新项 待办事项 待办事项 PUT /api/todoitems/{id} 更新现有项 待办事项 None DELETE /api/todoitems/{id}     删除项 None None

下图显示了应用的设计。

先决条件 Visual Studio Visual Studio Code Visual Studio for Mac 带有 ASP.NET 和 Web 开发工作负载的 Visual Studio 2022。 .NET 6.0 SDK Visual Studio Code 用于 Visual Studio Code 的 C#(最新版本) .NET 6.0 SDK

Visual Studio Code 说明使用用于 ASP.NET Core 的 .NET CLI 开发功能,如项目创建。 可在(macOS、Linux 或 Windows)上或在任何代码编辑器中遵循这些说明。 如果使用 Visual Studio Code 以外的其他内容,则可能需要进行少量更改。

Visual Studio 2022 for Mac 最新预览

重要

Microsoft 已宣布停用 Visual Studio for Mac。 从 2024 年 8 月 31 日起,将不再支持 Visual Studio for Mac。 替代方案包括:

带有 C# 开发工具包 和相关扩展(如 .NET MAUI 和 Unity)的 Visual Studio Code。 在 Mac 虚拟机中的 Windows 上运行的 Visual Studio IDE。 在云虚拟机中的 Windows 上运行的 Visual Studio IDE。

有关详细信息,请参阅 Visual Studio for Mac 停用公告。

创建 Web 项目 Visual Studio Visual Studio Code Visual Studio for Mac 从“文件”菜单中选择“新建”>“项目” 。 在搜索框中输入“Web API”。 选择“ASP.NET Core Web API”模板,然后选择“下一步”。 在“配置新项目”对话框中,将项目命名为“TodoApi”,然后选择“下一步”。 在“其他信息”对话框中: 确认“框架”为“.NET 6.0 (长期支持)”。 确认已选中“使用控制器(取消选中以使用最小 API)”。 选择“创建”。

打开集成终端。

将目录 (cd) 更改为包含项目文件夹的文件夹。

运行以下命令:

dotnet new webapi -o TodoApi cd TodoApi dotnet add package Microsoft.EntityFrameworkCore.InMemory code -r ../TodoApi

这些命令会:

创建新的 Web API 项目,并在 Visual Studio Code 中打开它。 添加下一部分所需的 NuGet 包。 在 Visual Studio Code 的当前实例中打开 TodoApi 文件夹。

Visual Studio Code 可能会显示一个对话框,询问:“你是否信任此文件夹中的文件作者?”

如果你信任父文件夹中的所有文件,请选择“信任父文件夹中所有文件的作者”。 选择“是,我信任所有作者”,因为项目文件夹包含 .NET 生成的文件。 当 Visual Studio Code 请求你添加资产来生成和调试项目时,请选择“是”。 如果 Visual Studio Code 不提供添加生成和调试资产的功能,请选择“视图”>“命令面板”,然后在搜索框中输入“.NET”。 从命令列表中选择 .NET: Generate Assets for Build and Debug 命令。

Visual Studio Code 添加一个包含生成的 launch.json 和 tasks.json 文件的 .vscode 文件夹。

选择“文件”>“新建解决方案”>。

在版本 8.6 之前的 Visual Studio for Mac 中,依次选择“.NET Core”>“应用”>“API”>“下一步”。 在版本 8.6 或更高版本中,依次选择“Web 和控制台”>“应用”>“API”>“下一步”。

在“配置新的 ASP.NET Core Web API”对话框中,选择最新的 .NET Core 5.x 目标框架。 选择“下一步”。

输入“TodoApi”作为“项目名称”,然后选择“创建”。

访问 Mac 上的命令终端

首次访问 Mac 上的命令终端需要以下设置配置:

导航到“系统首选项”>“键盘”>“快捷方式”>“服务”。 在“文件和文件夹”下,验证是否选中了“文件夹中的新终端”。

上述说明以两种方式实现访问命令终端:从 Visual Studio 内访问或通过查找器访问 。

若要从 Visual Studio for Mac 访问命令终端,请执行以下操作: 右键单击项目名称。 导航到“工具”>“在终端中打开”。 若要通过查找器访问命令终端,请执行以下操作: 右键单击所需文件夹。 在列表底部,选择“文件夹中的新终端”。

在项目文件夹中打开命令终端并运行以下命令:

dotnet add package Microsoft.EntityFrameworkCore.InMemory

注意

有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。

测试项目

项目模板创建了一个支持 Swagger 的 WeatherForecast API。

Visual Studio Visual Studio Code Visual Studio for Mac

按 Ctrl+F5 以在不使用调试程序的情况下运行。

如果尚未将项目配置为使用 SSL,Visual Studio 显示以下对话:

如果信任 IIS Express SSL 证书,请选择“是”。

将显示以下对话框:

如果你同意信任开发证书,请选择“是”。

有关信任 Firefox 浏览器的信息,请参阅 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE 证书错误。

Visual Studio 启动默认浏览器并导航到 https://localhost:/swagger/index.html,其中 是随机选择的端口号。

通过运行以下命令来信任 HTTPS 开发证书:

dotnet dev-certs https --trust

上述命令在 Linux 上无效。 有关信任证书的详细信息,请参阅 Linux 发行版的文档。

如果证书以前不受信任,上述命令显示以下对话:

如果你同意信任开发证书,请选择“是”。

有关详细信息,请参阅信任 ASP.NET Core HTTPS 开发证书。

有关信任 Firefox 浏览器的信息,请参阅 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE 证书错误。

运行应用:

按 Ctrl+F5。 在“选择环境”提示符下,选择“.NET Core”。 选择“添加配置”>“.NET: 启动本地 .NET Core 控制台应用”。 在配置 JSON 中: 将 替换为 net6.0。 将 替换为 TodoApi.dll。 按 Ctrl+F5。 在“找不到任务‘生成’”对话框中,选择“配置任务”。 选择“使用模板创建 tasks.json 文件”。 选择“.NET Core”任务模板。 按 Ctrl+F5。

在浏览器中,导航到 https://localhost:/swagger,其中 是显示在输出中的随机选择的端口号。

有关 Visual Studio for Mac,请参阅本教程的 .NET 5 版本。

随即显示 Swagger 页面 /swagger/index.html。 选择 GET >“试用”>“执行” 。 页面将显示:

用于测试 WeatherForecast API 的 Curl 命令。 用于测试 WeatherForecast API 的 URL。 响应代码、正文和标头。 包含媒体类型、示例值和架构的下拉列表框。

如果 Swagger 页面未显示,请参阅此 GitHub 问题。

Swagger 用于为 Web API 生成有用的文档和帮助页面。 本教程重点介绍如何创建 Web API。 有关 Swagger 的详细信息,请参阅包含 Swagger / OpenAPI 的 ASP.NET Core Web API 文档。

将请求 URL 复制粘贴到浏览器中:https://localhost:/weatherforecast

返回类似于以下示例的 JSON:

[ { "date": "2019-07-16T19:04:05.7257911-06:00", "temperatureC": 52, "temperatureF": 125, "summary": "Mild" }, { "date": "2019-07-17T19:04:05.7258461-06:00", "temperatureC": 36, "temperatureF": 96, "summary": "Warm" }, { "date": "2019-07-18T19:04:05.7258467-06:00", "temperatureC": 39, "temperatureF": 102, "summary": "Cool" }, { "date": "2019-07-19T19:04:05.7258471-06:00", "temperatureC": 10, "temperatureF": 49, "summary": "Bracing" }, { "date": "2019-07-20T19:04:05.7258474-06:00", "temperatureC": -1, "temperatureF": 31, "summary": "Chilly" } ] 更新 launchUrl

在 Properties\launchSettings.json 中,将 launchUrl 从 "swagger" 更新为 "api/todoitems":

"launchUrl": "api/todoitems",

由于将删除 Swagger,上述标记会将启动的 URL 更改为添加到以下部分的控制器的 GET 方法。

添加模型类

模型是一组表示应用管理的数据的类。 此应用的模型是单个 TodoItem 类。

Visual Studio Visual Studio Code Visual Studio for Mac

在“解决方案资源管理器”中,右键单击项目。 选择“添加”>“新建文件夹”。 将该文件夹命名为 Models注册一个免费试用帐户。

右键单击 Models 文件夹,然后选择“添加”>“类”。 将类命名为 TodoItem,然后选择“添加”。

将模板代码替换为以下内容:

添加名为 Models 的文件夹。

使用以下代码将 TodoItem.cs 文件添加到 Models 文件夹:

有关 Visual Studio for Mac,请参阅本教程的 .NET 5 版本。

namespace TodoApi.Models { public class TodoItem { public long Id { get; set; } public string? Name { get; set; } public bool IsComplete { get; set; } } }

Id 属性用作关系数据库中的唯一键。

模型类可位于项目的任意位置,但按照惯例会使用 Models 文件夹。

添加数据库上下文

数据库上下文是为数据模型协调 Entity Framework 功能的主类。 此类由 Microsoft.EntityFrameworkCore.DbContext 类派生而来。

Visual Studio Visual Studio Code Visual Studio for Mac 添加 NuGet 包 在“工具”菜单中,选择“NuGet 包管理器”>“管理解决方案的 NuGet 包”。 选择“浏览”选项卡,然后在搜索框中输入“Microsoft.EntityFrameworkCore.InMemory” 。 在左窗格中,选择“Microsoft.EntityFrameworkCore.InMemory”。 选中右窗格中的“项目”复选框,然后选择“安装” 。 添加 TodoContext 数据库上下文 右键单击 Models 文件夹,然后选择“添加”>“类”。 将类命名为 TodoContext,然后单击“添加”。 将 TodoContext.cs 文件添加到 Models 文件夹中。

有关 Visual Studio for Mac,请参阅本教程的 .NET 5 版本。

输入以下代码:

using Microsoft.EntityFrameworkCore; using System.Diagnostics.CodeAnalysis; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions options) : base(options) { } public DbSet TodoItems { get; set; } = null!; } } 注册数据库上下文

在 ASP.NET Core 中,服务(如数据库上下文)必须向依赖关系注入 (DI) 容器进行注册。 该容器向控制器提供服务。

使用以下代码更新 Program.cs:

using Microsoft.EntityFrameworkCore; using TodoApi.Models; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); builder.Services.AddDbContext(opt => opt.UseInMemoryDatabase("TodoList")); //builder.Services.AddSwaggerGen(c => //{ // c.SwaggerDoc("v1", new() { Title = "TodoApi", Version = "v1" }); //}); var app = builder.Build(); // Configure the HTTP request pipeline. if (builder.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); //app.UseSwagger(); //app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TodoApi v1")); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();

前面的代码:

删除 Swagger 调用。 删除未使用的 using 指令。 将数据库上下文添加到 DI 容器。 指定数据库上下文将使用内存中数据库。 构建控制器 Visual Studio Visual Studio Code Visual Studio for Mac

右键单击 Controllers 文件夹。

选择“添加”>“新建构建项”。

选择“其操作使用实体框架的 API 控制器”,然后选择“添加” 。

在“添加其操作使用实体框架的 API 控制器”对话框中:

在“模型类”中选择“TodoItem (TodoApi.Models)” 。 在“数据上下文类”中选择“TodoContext (TodoAPI.Models)” 。 选择“添加”。

如果基架操作失败,请选择“添加”以第二次尝试使用基架。

请确保目前所有更改均已保存。

从项目文件夹(即 TodoApi 文件夹)运行以下命令:

dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design dotnet add package Microsoft.EntityFrameworkCore.Design dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet tool install -g dotnet-aspnet-codegenerator dotnet aspnet-codegenerator controller -name TodoItemsController -async -api -m TodoItem -dc TodoContext -outDir Controllers

前面的命令:

添加构建所需的 NuGet 包。 安装构建引擎 (dotnet-aspnet-codegenerator)。 构建 TodoItemsController 基架。

注意

默认情况下,要安装的 .NET 二进制文件的体系结构表示当前运行的 OS 体系结构。 若要指定不同的 OS 体系结构,请参阅 dotnet tool install, --arch option。 有关详细信息,请参阅 GitHub 问题 dotnet/AspNetCore.Docs #29262。

有关 Visual Studio for Mac,请参阅本教程的 .NET 5 版本。

生成的代码:

使用 [ApiController] 属性标记类。 此属性指示控制器响应 Web API 请求。 有关该属性启用的特定行为的信息,请参阅使用 ASP.NET Core 创建 Web API。 使用 DI 将数据库上下文 (TodoContext) 注入到控制器中。 数据库上下文将在控制器中的每个 CRUD 方法中使用。

ASP.NET Core 模板:

具有视图的控制器在路由模板中包含 [action]。 API 控制器不在路由模板中包含 [action]。

如果 [action] 标记不在路由模板中,则从路由中排除操作名称。 也就是说,不会在匹配的路由中使用操作的关联方法名称。

更新 PostTodoItem create 方法

更新 PostTodoItem 中的 return 语句,以使用 nameof 运算符:

[HttpPost] public async Task PostTodoItem(TodoItem todoItem) { _context.TodoItems.Add(todoItem); await _context.SaveChangesAsync(); //return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem); return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem); }

前面的代码是 HTTP POST 方法,如 [HttpPost] 属性所指示。 该方法从 HTTP 请求正文获取待办事项的值。

有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

CreatedAtAction 方法:

如果成功,将返回 HTTP 201 状态代码。 HTTP 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。 向响应添加位置标头。 Location 标头指定新建的待办事项的 URI。 有关详细信息,请参阅创建的 10.2.2 201。 引用 GetTodoItem 操作以创建 Location 标头的 URI。 C# nameof 关键字用于避免在 CreatedAtAction 调用中硬编码操作名称。

安装 http-repl

本教程使用 http-repl 测试 Web API。

在命令提示符下运行以下命令:

dotnet tool install -g Microsoft.dotnet-httprepl

注意

默认情况下,要安装的 .NET 二进制文件的体系结构表示当前运行的 OS 体系结构。 若要指定不同的 OS 体系结构,请参阅 dotnet tool install, --arch option。 有关详细信息,请参阅 GitHub 问题 dotnet/AspNetCore.Docs #29262。

如果尚未安装 .NET 6.0 SDK 或运行时,请安装 .NET 6.0 运行时。

测试 PostTodoItem

按 Ctrl+F5 运行应用。

打开新的端子窗口并运行以下命令。 如果你的应用使用不同的端口号,请将 httprepl 命令中的 5001 替换为你的端口号。

httprepl https://localhost:5001/api/todoitems post -h Content-Type=application/json -c "{"name":"walk dog","isComplete":true}"

下面是该命令输出的示例:

HTTP/1.1 201 Created Content-Type: application/json; Date: Tue, 07 Sep 2021 20:39:47 GMT Location: https://localhost:5001/api/TodoItems/1 Server: Kestrel Transfer-Encoding: chunked { "id": 1, "name": "walk dog", "isComplete": true } 测试位置标头 URI

若要测试位置标头,请将其复制并粘贴到 httprepl get 命令中。

下面的示例假定你仍在 httprepl 会话中。 如果你结束了之前的 httprepl 会话,请在以下命令中将 connect 替换为 httprepl:

connect https://localhost:5001/api/todoitems/1 get

下面是该命令输出的示例:

HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Date: Tue, 07 Sep 2021 20:48:10 GMT Server: Kestrel Transfer-Encoding: chunked { "id": 1, "name": "walk dog", "isComplete": true } 检查 GET 方法

实现了两个 GET 终结点:

GET /api/todoitems GET /api/todoitems/{id}

你刚刚看到了 /api/todoitems/{id} 路由的示例。 测试 /api/todoitems 路由:

connect https://localhost:5001/api/todoitems get

下面是该命令输出的示例:

HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Date: Tue, 07 Sep 2021 20:59:21 GMT Server: Kestrel Transfer-Encoding: chunked [ { "id": 1, "name": "walk dog", "isComplete": true } ]

此时,返回的 JSON 是一个项数组。

此应用使用内存中数据库。 如果应用已停止并启动,则前面的 GET 请求将不会返回任何数据。 如果未返回任何数据,将数据 POST 到应用。

路由和 URL 路径

[HttpGet] 特性表示对 HTTP GET 请求进行响应的方法。 每个方法的 URL 路径构造如下所示:

在控制器的 Route 属性中以模板字符串开头:

[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase

将 [controller] 替换为控制器的名称,按照惯例,在控制器类名称中去掉“Controller”后缀。 对于此示例,控制器类名称为“TodoItems”控制器,因此控制器名称为“TodoItems”。 ASP.NET Core 路由不区分大小写。

如果 [HttpGet] 属性具有路由模板(例如 [HttpGet("products")]),则将它追加到路径。 此示例不使用模板。 有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

在下面的 GetTodoItem 方法中,"{id}" 是待办事项的唯一标识符的占位符变量。 调用 GetTodoItem 时,URL 中 "{id}" 的值会在 id 参数中提供给方法。

[HttpGet("{id}")] public async Task GetTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } return todoItem; } 返回值

GetTodoItems 和 GetTodoItem 方法的返回类型是 ActionResult 类型。 ASP.NET Core 自动将对象序列化为 JSON,并将 JSON 写入响应消息的正文中。 此返回类型的响应代码为 200 OK(假设没有未处理的异常)。 未经处理的异常将转换为 5xx 错误。

ActionResult 返回类型可以表示大范围的 HTTP 状态代码。 例如,GetTodoItem 可以返回两个不同的状态值:

如果没有任何项与请求的 ID 匹配,该方法将返回 404 状态NotFound错误代码。 否则,此方法将返回具有 JSON 响应正文的 200。 返回 item 则产生 HTTP 200 响应。 PutTodoItem 方法

检查 PutTodoItem 方法:

[HttpPut("{id}")] public async Task PutTodoItem(long id, TodoItem todoItem) { if (id != todoItem.Id) { return BadRequest(); } _context.Entry(todoItem).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!TodoItemExists(id)) { return NotFound(); } else { throw; } } return NoContent(); }

PutTodoItem 与 PostTodoItem 类似,但是使用的是 HTTP PUT。 响应是 204(无内容)。 根据 HTTP 规范,PUT 请求需要客户端发送整个更新的实体,而不仅仅是更改。 若要支持部分更新,请使用 HTTP PATCH。

如果在下一节中调用 PutTodoItem 时出错,请调用 GET 以确保数据库中有项目。

测试 PutTodoItem 方法

本示例使用内存内、数据库,每次启动应用时都必须对其进行初始化。 在进行 PUT 调用之前,数据库中必须有一个项。 调用 GET,以确保在调用 PUT 之前数据库中存在项。

更新 ID 为 1 的待办事项并将其名称设置为 "feed fish":

connect https://localhost:5001/api/todoitems/1 put -h Content-Type=application/json -c "{"id":1,"name":"feed fish","isComplete":true}"

下面是该命令输出的示例:

HTTP/1.1 204 No Content Date: Tue, 07 Sep 2021 21:20:47 GMT Server: Kestrel DeleteTodoItem 方法

检查 DeleteTodoItem 方法:

[HttpDelete("{id}")] public async Task DeleteTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } _context.TodoItems.Remove(todoItem); await _context.SaveChangesAsync(); return NoContent(); } 测试 DeleteTodoItem 方法

删除 Id = 1 的待办事项:

connect https://localhost:5001/api/todoitems/1 delete

下面是该命令输出的示例:

HTTP/1.1 204 No Content Date: Tue, 07 Sep 2021 21:43:00 GMT Server: Kestrel

防止过度发布

目前,示例应用公开了整个 TodoItem 对象。 生产应用通常使用模型的子集来限制输入和返回的数据。 这背后有多种原因,但安全性是主要原因。 模型的子集通常称为数据传输对象 (DTO)、输入模型或视图模型。 本教程使用了 DTO。

DTO 可用于:

防止过度发布。 隐藏客户端不应查看的属性。 省略一些属性以缩减有效负载大小。 平展包含嵌套对象的对象图。 对客户端而言,平展的对象图可能更方便。

若要演示 DTO 方法,请更新 TodoItem 类,使其包含机密字段:

namespace TodoApi.Models { public class TodoItem { public long Id { get; set; } public string? Name { get; set; } public bool IsComplete { get; set; } public string? Secret { get; set; } } }

此应用需要隐藏机密字段,但管理应用可以选择公开它。

确保可以发布和获取机密字段。

创建 DTO 模型:

namespace TodoApi.Models { public class TodoItemDTO { public long Id { get; set; } public string? Name { get; set; } public bool IsComplete { get; set; } } }

更新 TodoItemsController 以使用 TodoItemDTO:

using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TodoApi.Models; namespace TodoApi.Controllers { [Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase { private readonly TodoContext _context; public TodoItemsController(TodoContext context) { _context = context; } // GET: api/TodoItems [HttpGet] public async Task GetTodoItems() { return await _context.TodoItems .Select(x => ItemToDTO(x)) .ToListAsync(); } // GET: api/TodoItems/5 [HttpGet("{id}")] public async Task GetTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } return ItemToDTO(todoItem); } // PUT: api/TodoItems/5 // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 [HttpPut("{id}")] public async Task UpdateTodoItem(long id, TodoItemDTO todoItemDTO) { if (id != todoItemDTO.Id) { return BadRequest(); } var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } todoItem.Name = todoItemDTO.Name; todoItem.IsComplete = todoItemDTO.IsComplete; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) when (!TodoItemExists(id)) { return NotFound(); } return NoContent(); } // POST: api/TodoItems // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 [HttpPost] public async Task CreateTodoItem(TodoItemDTO todoItemDTO) { var todoItem = new TodoItem { IsComplete = todoItemDTO.IsComplete, Name = todoItemDTO.Name }; _context.TodoItems.Add(todoItem); await _context.SaveChangesAsync(); return CreatedAtAction( nameof(GetTodoItem), new { id = todoItem.Id }, ItemToDTO(todoItem)); } // DELETE: api/TodoItems/5 [HttpDelete("{id}")] public async Task DeleteTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } _context.TodoItems.Remove(todoItem); await _context.SaveChangesAsync(); return NoContent(); } private bool TodoItemExists(long id) { return _context.TodoItems.Any(e => e.Id == id); } private static TodoItemDTO ItemToDTO(TodoItem todoItem) => new TodoItemDTO { Id = todoItem.Id, Name = todoItem.Name, IsComplete = todoItem.IsComplete }; } }

确保无法发布或获取机密字段。

使用 JavaScript 调用 Web API

请参阅教程:使用 JavaScript 调用 ASP.NET Core Web API。

Web API 视频系列

请参阅视频:初学者系列:Web API。

向 Web API 添加身份验证支持

ASP.NET Core Identity 将用户界面 (UI) 登录功能添加到 ASP.NET Core Web 应用。 若要保护 Web API 和 SPA,请使用以下项之一:

Microsoft Entra ID Azure Active Directory B2C (Azure AD B2C) Duende Identity Server

Duende Identity Server 是适用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 框架。 Duende Identity Server 支持以下安全功能:

身份验证即服务 (AaaS) 跨多个应用程序类型的单一登录/注销 (SSO) API 的访问控制 Federation Gateway

重要事项

Duende Software 可能会要求你为 Duende Identity Server 的生产使用支付许可证费用。 有关详细信息,请参阅从 ASP.NET Core 5.0 迁移到 6.0。

有关详细信息,请参阅 Duende Identity Server 文档(Duende Software 网站)。

发布到 Azure

有关部署到 Azure 的信息,请参阅快速入门:部署 ASP.NET Web 应用。

其他资源

查看或下载本教程的示例代码。 请参阅如何下载。

有关更多信息,请参见以下资源:

使用 ASP.NET Core 创建 Web API 教程:使用 ASP.NET Core 创建最小 API 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档 RazorASP.NET Core 中的 Pages 和 Entity Framework Core - 第 1 个教程(共 8 个) 在 ASP.NET Core 中路由到控制器操作 ASP.NET Core Web API 中控制器操作的返回类型 将 ASP.NET Core 应用部署到 Azure 应用服务 托管和部署 ASP.NET Core 使用 ASP.NET Core 创建 Web API

本教程介绍生成使用数据库的基于控制器的 Web API 的基础知识。 在 ASP.NET Core 中创建 API 的另一种方法是创建最小 API。 有关在最小 API 和基于控制器的 API 之间进行选择的帮助,请参阅 API 概述。 有关创建最小 API 的教程,请参阅教程:使用 ASP.NET Core 创建最小 API。

在本教程中,你将了解:

创建 Web API 项目。 添加模型类和数据库上下文。 使用 CRUD 方法构建控制器。 配置路由、URL 路径和返回值。 使用 Postman 调用 Web API。

在结束时,你会获得可以管理存储在数据库中的“待办事项”的 Web API。

概述

本教程将创建以下 API:

API 描述 请求正文 响应正文 GET /api/todoitems 获取所有待办事项 None 待办事项的数组 GET /api/todoitems/{id} 按 ID 获取项 None 待办事项 POST /api/todoitems 添加新项 待办事项 待办事项 PUT /api/todoitems/{id} 更新现有项 待办事项 None DELETE /api/todoitems/{id}     删除项 None None

下图显示了应用的设计。

先决条件 Visual Studio Visual Studio Code Visual Studio for Mac 具有“ASP.NET 和 Web 开发”工作负载的 Visual Studio 2019 16.8 或更高版本 .NET 5.0 SDK Visual Studio Code C# for Visual Studio Code(最新版本) .NET 5.0 SDK

Visual Studio Code 说明使用用于 ASP.NET Core 的 .NET CLI 开发功能,如项目创建。 可在(macOS、Linux 或 Windows)上或在任何代码编辑器中遵循这些说明。 如果使用 Visual Studio Code 以外的其他内容,则可能需要进行少量更改。

Visual Studio for Mac .NET 5.0 SDK 创建 Web 项目 Visual Studio Visual Studio Code Visual Studio for Mac 从“文件”菜单中选择“新建”>“项目” 。 选择“ASP.NET Core Web API”模板,然后单击“下一步” 。 将项目命名为 TodoApi,然后单击“创建”。 在“创建新的 ASP.NET Core Web 应用程序”对话框中,确认选择 .NET Core 和 ASP.NET Core 5.0 。 选择“API”模板,然后单击“创建”。

打开集成终端。

将目录 (cd) 更改为包含项目文件夹的文件夹。

运行以下命令:

dotnet new webapi -o TodoApi cd TodoApi dotnet add package Microsoft.EntityFrameworkCore.InMemory code -r ../TodoApi

这些命令会:

创建新的 Web API 项目,并在 Visual Studio Code 中打开它。 添加下一部分所需的 NuGet 包。 在 Visual Studio Code 的当前实例中打开 TodoApi 文件夹。

Visual Studio Code 可能会显示一个对话框,询问:“你是否信任此文件夹中的文件作者?”

如果你信任父文件夹中的所有文件,请选择“信任父文件夹中所有文件的作者”。 选择“是,我信任所有作者”,因为项目文件夹包含 .NET 生成的文件。 当 Visual Studio Code 请求你添加资产来生成和调试项目时,请选择“是”。 如果 Visual Studio Code 不提供添加生成和调试资产的功能,请选择“视图”>“命令面板”,然后在搜索框中输入“.NET”。 从命令列表中选择 .NET: Generate Assets for Build and Debug 命令。

Visual Studio Code 添加一个包含生成的 launch.json 和 tasks.json 文件的 .vscode 文件夹。

选择“文件”>“新建解决方案”>。

在版本 8.6 之前的 Visual Studio for Mac 中,依次选择“.NET Core”>“应用”>“API”>“下一步”。 在版本 8.6 或更高版本中,依次选择“Web 和控制台”>“应用”>“API”>“下一步”。

在“配置新的 ASP.NET Core Web API”对话框中,选择最新的 .NET Core 5.x 目标框架。 选择“下一步”。

输入“TodoApi”作为“项目名称”,然后选择“创建”。

访问 Mac 上的命令终端

首次访问 Mac 上的命令终端需要以下设置配置:

导航到“系统首选项”>“键盘”>“快捷方式”>“服务”。 在“文件和文件夹”下,验证是否选中了“文件夹中的新终端”。

上述说明以两种方式实现访问命令终端:从 Visual Studio 内访问或通过查找器访问 。

若要从 Visual Studio for Mac 访问命令终端,请执行以下操作: 右键单击项目名称。 导航到“工具”>“在终端中打开”。 若要通过查找器访问命令终端,请执行以下操作: 右键单击所需文件夹。 在列表底部,选择“文件夹中的新终端”。

在项目文件夹中打开命令终端并运行以下命令:

dotnet add package Microsoft.EntityFrameworkCore.InMemory

注意

有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。

测试项目

项目模板创建了一个支持 Swagger 的 WeatherForecast API。

Visual Studio Visual Studio Code Visual Studio for Mac

按 Ctrl+F5 以在不使用调试程序的情况下运行。

如果尚未将项目配置为使用 SSL,Visual Studio 显示以下对话:

如果信任 IIS Express SSL 证书,请选择“是”。

将显示以下对话框:

如果你同意信任开发证书,请选择“是”。

有关信任 Firefox 浏览器的信息,请参阅 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE 证书错误。

Visual Studio 将启动:

IIS Express Web 服务器。 默认浏览器,并导航到 https://localhost:/swagger/index.html,其中 是随机选择的端口号。

通过运行以下命令来信任 HTTPS 开发证书:

dotnet dev-certs https --trust

上述命令在 Linux 上无效。 有关信任证书的详细信息,请参阅 Linux 发行版的文档。

如果证书以前不受信任,上述命令显示以下对话:

如果你同意信任开发证书,请选择“是”。

有关详细信息,请参阅信任 ASP.NET Core HTTPS 开发证书。

有关信任 Firefox 浏览器的信息,请参阅 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE 证书错误。

按 Ctrl+F5 运行应用。 在浏览器中,转到以下 URL:https://localhost:5001/swagger

选择“运行”>“开始调试”以启动应用。 Visual Studio for Mac 会启动浏览器并导航到 https://localhost:,其中 是随机选择的端口号。 将返回 HTTP 404(未找到)错误。 将 /swagger 追加到 URL(将 URL 更改为 https://localhost:/swagger)。

随即显示 Swagger 页面 /swagger/index.html。 选择 GET >“试用”>“执行” 。 页面将显示:

用于测试 WeatherForecast API 的 Curl 命令。 用于测试 WeatherForecast API 的 URL。 响应代码、正文和标头。 包含媒体类型、示例值和架构的下拉列表框。

如果 Swagger 页面未显示,请参阅此 GitHub 问题。

Swagger 用于为 Web API 生成有用的文档和帮助页面。 本教程重点介绍如何创建 Web API。 有关 Swagger 的详细信息,请参阅包含 Swagger / OpenAPI 的 ASP.NET Core Web API 文档。

将请求 URL 复制粘贴到浏览器中:https://localhost:/weatherforecast

返回类似于以下项的 JSON:

[ { "date": "2019-07-16T19:04:05.7257911-06:00", "temperatureC": 52, "temperatureF": 125, "summary": "Mild" }, { "date": "2019-07-17T19:04:05.7258461-06:00", "temperatureC": 36, "temperatureF": 96, "summary": "Warm" }, { "date": "2019-07-18T19:04:05.7258467-06:00", "temperatureC": 39, "temperatureF": 102, "summary": "Cool" }, { "date": "2019-07-19T19:04:05.7258471-06:00", "temperatureC": 10, "temperatureF": 49, "summary": "Bracing" }, { "date": "2019-07-20T19:04:05.7258474-06:00", "temperatureC": -1, "temperatureF": 31, "summary": "Chilly" } ] 更新 launchUrl

在 Properties\launchSettings.json 中,将 launchUrl 从 "swagger" 更新为 "api/todoitems":

"launchUrl": "api/todoitems",

由于将删除 Swagger,上述标记会将启动的 URL 更改为添加到以下部分的控制器的 GET 方法。

添加模型类

模型是一组表示应用管理的数据的类。 此应用的模型是单个 TodoItem 类。

Visual Studio Visual Studio Code Visual Studio for Mac

在“解决方案资源管理器”中,右键单击项目。 选择“添加”>“新建文件夹”。 将该文件夹命名为 Models注册一个免费试用帐户。

右键单击 Models 文件夹,然后选择“添加”>“类”。 将类命名为 TodoItem,然后选择“添加”。

将模板代码替换为以下内容:

添加名为 Models 的文件夹。

使用以下代码将 TodoItem 类添加到 Models 文件夹:

右键单击项目。 选择“添加”>“新建文件夹”。 将该文件夹命名为 Models注册一个免费试用帐户。

右键单击 Models 文件夹,然后选择“添加”>“新建文件”>“常规”>“空类”。

将类命名为“TodoItem”,然后单击“新建”。

将模板代码替换为以下内容:

namespace TodoApi.Models { public class TodoItem { public long Id { get; set; } public string Name { get; set; } public bool IsComplete { get; set; } } }

Id 属性用作关系数据库中的唯一键。

模型类可位于项目的任意位置,但按照惯例会使用 Models 文件夹。

添加数据库上下文

数据库上下文是为数据模型协调 Entity Framework 功能的主类。 此类由 Microsoft.EntityFrameworkCore.DbContext 类派生而来。

Visual Studio Visual Studio Code / Visual Studio for Mac 添加 NuGet 包 在“工具”菜单中,选择“NuGet 包管理器”>“管理解决方案的 NuGet 包”。 选择“浏览”选项卡,然后在搜索框中输入“Microsoft.EntityFrameworkCore.InMemory” 。 在左窗格中,选择“Microsoft.EntityFrameworkCore.InMemory”。 选中右窗格中的“项目”复选框,然后选择“安装” 。

添加 TodoContext 数据库上下文 右键单击 Models 文件夹,然后选择“添加”>“类”。 将类命名为 TodoContext,然后单击“添加”。 将 TodoContext 类添加到 Models 文件夹。

输入以下代码:

using Microsoft.EntityFrameworkCore; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions options) : base(options) { } public DbSet TodoItems { get; set; } } } 注册数据库上下文

在 ASP.NET Core 中,服务(如数据库上下文)必须向依赖关系注入 (DI) 容器进行注册。 该容器向控制器提供服务。

使用以下代码更新 Startup.cs:

// Unused usings removed using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.EntityFrameworkCore; using TodoApi.Models; namespace TodoApi { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddDbContext(opt => opt.UseInMemoryDatabase("TodoList")); //services.AddSwaggerGen(c => //{ // c.SwaggerDoc("v1", new OpenApiInfo { Title = "TodoApi", Version = "v1" }); //}); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); //app.UseSwagger(); //app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TodoApi v1")); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } }

前面的代码:

删除 Swagger 调用。 删除未使用的 using 声明。 将数据库上下文添加到 DI 容器。 指定数据库上下文将使用内存中数据库。 构建控制器 Visual Studio Visual Studio Code / Visual Studio for Mac

右键单击 Controllers 文件夹。

选择“添加”>“新建构建项”。

选择“其操作使用实体框架的 API 控制器”,然后选择“添加” 。

在“添加其操作使用实体框架的 API 控制器”对话框中:

在“模型类”中选择“TodoItem (TodoApi.Models)” 。 在“数据上下文类”中选择“TodoContext (TodoAPI.Models)” 。 选择“添加”。

从项目文件夹 TodoApi/TodoApi 目录运行以下命令:

dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design dotnet add package Microsoft.EntityFrameworkCore.Design dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet tool install -g dotnet-aspnet-codegenerator dotnet aspnet-codegenerator controller -name TodoItemsController -async -api -m TodoItem -dc TodoContext -outDir Controllers

前面的命令:

添加构建所需的 NuGet 包。 安装构建引擎 (dotnet-aspnet-codegenerator)。 构建 TodoItemsController。

注意

默认情况下,要安装的 .NET 二进制文件的体系结构表示当前运行的 OS 体系结构。 若要指定不同的 OS 体系结构,请参阅 dotnet tool install, --arch option。 有关详细信息,请参阅 GitHub 问题 dotnet/AspNetCore.Docs #29262。

生成的代码:

使用 [ApiController] 属性标记类。 此属性指示控制器响应 Web API 请求。 有关该属性启用的特定行为的信息,请参阅使用 ASP.NET Core 创建 Web API。 使用 DI 将数据库上下文 (TodoContext) 注入到控制器中。 数据库上下文将在控制器中的每个 CRUD 方法中使用。

ASP.NET Core 模板:

具有视图的控制器在路由模板中包含 [action]。 API 控制器不在路由模板中包含 [action]。

如果 [action] 标记不在路由模板中,则从路由中排除操作名称。 也就是说,不会在匹配的路由中使用操作的关联方法名称。

更新 PostTodoItem create 方法

更新 PostTodoItem 中的 return 语句,以使用 nameof 运算符:

// POST: api/TodoItems [HttpPost] public async Task PostTodoItem(TodoItem todoItem) { _context.TodoItems.Add(todoItem); await _context.SaveChangesAsync(); //return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem); return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem); }

前面的代码是 HTTP POST 方法,如 [HttpPost] 属性所指示。 该方法从 HTTP 请求正文获取待办事项的值。

有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

CreatedAtAction 方法:

如果成功,将返回 HTTP 201 状态代码。 HTTP 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。 向响应添加位置标头。 Location 标头指定新建的待办事项的 URI。 有关详细信息,请参阅创建的 201。 引用 GetTodoItem 操作以创建 Location 标头的 URI。 C# nameof 关键字用于避免在 CreatedAtAction 调用中硬编码操作名称。

安装 Postman

本教程使用 Postman 测试 Web API。

安装 Postman 启动 Web 应用。 启动 Postman。 禁用“SSL 证书验证”: Postman for Windows:选择“文件”>“设置”(“常规”选项卡),禁用“SSL 证书验证”。 Postman for macOS:选择“Postman”>“设置”(“常规”选项卡),禁用“SSL 证书验证”。

警告

在测试控制器之后重新启用 SSL 证书验证。

通过 Postman 测试 PostTodoItem

创建新请求。

将 HTTP 方法设置为 POST。

将 URI 设置为 https://localhost:/api/todoitems。 例如 https://localhost:5001/api/todoitems。

选择“正文”选项卡。

选择“原始”单选按钮。

将类型设置为 JSON (application/json)。

在请求正文中,输入待办事项的 JSON:

{ "name":"walk dog", "isComplete":true }

选择Send。

测试位置标头 URI

你可以在浏览器中测试位置标头 URI。 将位置标头 URI 复制粘贴到浏览器中。

若要在 Postman 中测试,请执行以下操作:

在Headers 窗格中选择Response 选项卡。

复制Location 标头值:

将 HTTP 方法设置为 GET。

将 URI 设置为 https://localhost:/api/todoitems/1。 例如 https://localhost:5001/api/todoitems/1。

选择Send。

检查 GET 方法

实现了两个 GET 终结点:

GET /api/todoitems GET /api/todoitems/{id}

通过从浏览器或 Postman 调用两个终结点来测试应用。 例如:

https://localhost:5001/api/todoitems https://localhost:5001/api/todoitems/1

对 GetTodoItems 的调用生成类似于以下项的响应:

[ { "id": 1, "name": "Item1", "isComplete": false } ] 使用 Postman 测试 Get 创建新请求。 将 HTTP 方法设置为“GET”。 将请求 URI 设置为 https://localhost:/api/todoitems。 例如 https://localhost:5001/api/todoitems。 在 Postman 中设置Two pane view 。 选择Send。

此应用使用内存中数据库。 如果应用已停止并启动,则前面的 GET 请求将不会返回任何数据。 如果未返回任何数据,将数据 POST 到应用。

路由和 URL 路径

[HttpGet] 特性表示对 HTTP GET 请求进行响应的方法。 每个方法的 URL 路径构造如下所示:

在控制器的 Route 属性中以模板字符串开头:

[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase { private readonly TodoContext _context; public TodoItemsController(TodoContext context) { _context = context; }

将 [controller] 替换为控制器的名称,按照惯例,在控制器类名称中去掉“Controller”后缀。 对于此示例,控制器类名称为“TodoItems”控制器,因此控制器名称为“TodoItems”。 ASP.NET Core 路由不区分大小写。

如果 [HttpGet] 属性具有路由模板(例如 [HttpGet("products")]),则将它追加到路径。 此示例不使用模板。 有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

在下面的 GetTodoItem 方法中,"{id}" 是待办事项的唯一标识符的占位符变量。 调用 GetTodoItem 时,URL 中 "{id}" 的值会在 id 参数中提供给方法。

// GET: api/TodoItems/5 [HttpGet("{id}")] public async Task GetTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } return todoItem; } 返回值

GetTodoItems 和 GetTodoItem 方法的返回类型是 ActionResult 类型。 ASP.NET Core 自动将对象序列化为 JSON,并将 JSON 写入响应消息的正文中。 此返回类型的响应代码为 200 OK(假设没有未处理的异常)。 未经处理的异常将转换为 5xx 错误。

ActionResult 返回类型可以表示大范围的 HTTP 状态代码。 例如,GetTodoItem 可以返回两个不同的状态值:

如果没有任何项与请求的 ID 匹配,该方法将返回 404 状态NotFound错误代码。 否则,此方法将返回具有 JSON 响应正文的 200。 返回 item 则产生 HTTP 200 响应。 PutTodoItem 方法

检查 PutTodoItem 方法:

// PUT: api/TodoItems/5 [HttpPut("{id}")] public async Task PutTodoItem(long id, TodoItem todoItem) { if (id != todoItem.Id) { return BadRequest(); } _context.Entry(todoItem).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!TodoItemExists(id)) { return NotFound(); } else { throw; } } return NoContent(); }

PutTodoItem 与 PostTodoItem 类似,但是使用的是 HTTP PUT。 响应是 204(无内容)。 根据 HTTP 规范,PUT 请求需要客户端发送整个更新的实体,而不仅仅是更改。 若要支持部分更新,请使用 HTTP PATCH。

如果在调用 PutTodoItem 时出错,请调用 GET 以确保数据库中有项目。

测试 PutTodoItem 方法

本示例使用内存内、数据库,每次启动应用时都必须对其进行初始化。 在进行 PUT 调用之前,数据库中必须有一个项。 调用 GET,以确保在调用 PUT 之前数据库中存在项。

更新 ID 为 1 的待办事项并将其名称设置为 "feed fish":

{ "Id":1, "name":"feed fish", "isComplete":true }

下图显示 Postman 更新:

DeleteTodoItem 方法

检查 DeleteTodoItem 方法:

// DELETE: api/TodoItems/5 [HttpDelete("{id}")] public async Task DeleteTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } _context.TodoItems.Remove(todoItem); await _context.SaveChangesAsync(); return NoContent(); } 测试 DeleteTodoItem 方法

使用 Postman 删除待办事项:

将方法设置为 DELETE。 设置要删除的对象的 URI,例如 https://localhost:5001/api/todoitems/1。 选择Send。

防止过度发布

目前,示例应用公开了整个 TodoItem 对象。 生产应用通常使用模型的子集来限制输入和返回的数据。 这背后有多种原因,但安全性是主要原因。 模型的子集通常称为数据传输对象 (DTO)、输入模型或视图模型。 本文使用的是 DTO。

DTO 可用于:

防止过度发布。 隐藏客户端不应查看的属性。 省略一些属性以缩减有效负载大小。 平展包含嵌套对象的对象图。 对客户端而言,平展的对象图可能更方便。

若要演示 DTO 方法,请更新 TodoItem 类,使其包含机密字段:

namespace TodoApi.Models { public class TodoItem { public long Id { get; set; } public string Name { get; set; } public bool IsComplete { get; set; } public string Secret { get; set; } } }

此应用需要隐藏机密字段,但管理应用可以选择公开它。

确保可以发布和获取机密字段。

创建 DTO 模型:

public class TodoItemDTO { public long Id { get; set; } public string Name { get; set; } public bool IsComplete { get; set; } }

更新 TodoItemsController 以使用 TodoItemDTO:

// GET: api/TodoItems [HttpGet] public async Task GetTodoItems() { return await _context.TodoItems .Select(x => ItemToDTO(x)) .ToListAsync(); } [HttpGet("{id}")] public async Task GetTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } return ItemToDTO(todoItem); } [HttpPut("{id}")] public async Task UpdateTodoItem(long id, TodoItemDTO todoItemDTO) { if (id != todoItemDTO.Id) { return BadRequest(); } var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } todoItem.Name = todoItemDTO.Name; todoItem.IsComplete = todoItemDTO.IsComplete; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) when (!TodoItemExists(id)) { return NotFound(); } return NoContent(); } [HttpPost] public async Task CreateTodoItem(TodoItemDTO todoItemDTO) { var todoItem = new TodoItem { IsComplete = todoItemDTO.IsComplete, Name = todoItemDTO.Name }; _context.TodoItems.Add(todoItem); await _context.SaveChangesAsync(); return CreatedAtAction( nameof(GetTodoItem), new { id = todoItem.Id }, ItemToDTO(todoItem)); } [HttpDelete("{id}")] public async Task DeleteTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } _context.TodoItems.Remove(todoItem); await _context.SaveChangesAsync(); return NoContent(); } private bool TodoItemExists(long id) => _context.TodoItems.Any(e => e.Id == id); private static TodoItemDTO ItemToDTO(TodoItem todoItem) => new TodoItemDTO { Id = todoItem.Id, Name = todoItem.Name, IsComplete = todoItem.IsComplete };

确保无法发布或获取机密字段。

使用 JavaScript 调用 Web API

请参阅教程:使用 JavaScript 调用 ASP.NET Core Web API。

向 Web API 添加身份验证支持

ASP.NET Core Identity 将用户界面 (UI) 登录功能添加到 ASP.NET Core Web 应用。 若要保护 Web API 和 SPA,请使用以下项之一:

Microsoft Entra ID Azure Active Directory B2C (Azure AD B2C) Duende Identity Server

Duende Identity Server 是适用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 框架。 Duende Identity Server 支持以下安全功能:

身份验证即服务 (AaaS) 跨多个应用程序类型的单一登录/注销 (SSO) API 的访问控制 Federation Gateway

重要事项

Duende Software 可能会要求你为 Duende Identity Server 的生产使用支付许可证费用。 有关详细信息,请参阅从 ASP.NET Core 5.0 迁移到 6.0。

有关详细信息,请参阅 Duende Identity Server 文档(Duende Software 网站)。

发布到 Azure

有关部署到 Azure 的信息,请参阅快速入门:部署 ASP.NET Web 应用。

其他资源

查看或下载本教程的示例代码。 请参阅如何下载。

有关更多信息,请参见以下资源:

使用 ASP.NET Core 创建 Web API 教程:使用 ASP.NET Core 创建最小 API 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档 RazorASP.NET Core 中的 Pages 和 Entity Framework Core - 第 1 个教程(共 8 个) 在 ASP.NET Core 中路由到控制器操作 ASP.NET Core Web API 中控制器操作的返回类型 将 ASP.NET Core 应用部署到 Azure 应用服务 托管和部署 ASP.NET Core 使用 ASP.NET Core 创建 Web API

本教程介绍生成使用数据库的基于控制器的 Web API 的基础知识。 在 ASP.NET Core 中创建 API 的另一种方法是创建最小 API。 有关在最小 API 和基于控制器的 API 之间进行选择的帮助,请参阅 API 概述。 有关创建最小 API 的教程,请参阅教程:使用 ASP.NET Core 创建最小 API。

在本教程中,你将了解:

创建 Web API 项目。 添加模型类和数据库上下文。 使用 CRUD 方法构建控制器。 配置路由、URL 路径和返回值。 使用 Postman 调用 Web API。

在结束时,你会获得可以管理存储在数据库中的“待办事项”的 Web API。

概述

本教程将创建以下 API:

API 描述 请求正文 响应正文 GET /api/todoitems 获取所有待办事项 None 待办事项的数组 GET /api/todoitems/{id} 按 ID 获取项 None 待办事项 POST /api/todoitems 添加新项 待办事项 待办事项 PUT /api/todoitems/{id} 更新现有项 待办事项 None DELETE /api/todoitems/{id}     删除项 None None

下图显示了应用的设计。

先决条件 Visual Studio Visual Studio Code Visual Studio for Mac 具有“ASP.NET 和 Web 开发”工作负载的 Visual Studio 2019 16.4 或更高版本 .NET Core 3.1 SDK Visual Studio Code 用于 Visual Studio Code 的 C#(最新版本) .NET Core 3.1 SDK

Visual Studio Code 说明使用用于 ASP.NET Core 的 .NET Core CLI 开发功能,如项目创建。 可在任何平台(macOS、Linux 或 Windows)上或在任何代码编辑器中遵循这些说明。 如果使用 Visual Studio Code 以外的其他内容,则可能需要进行少量更改。 有关在 macOS 上安装 Visual Studio Code 的详细信息,请参阅 macOS 上的 Visual Studio Code。

Visual Studio for Mac 版本 8.4 或更高版本 .NET Core 3.1 SDK 创建 Web 项目 Visual Studio Visual Studio Code Visual Studio for Mac 从“文件”菜单中选择“新建”>“项目” 。 选择“ASP.NET Core Web 应用程序”模板,再单击“下一步” 。 将项目命名为 TodoApi,然后单击“创建”。 在“创建新的 ASP.NET Core Web 应用程序”对话框中,确认选择“.NET Core”和“ASP.NET Core 3.1” 。 选择“API”模板,然后单击“创建”。

打开集成终端。

将目录 (cd) 更改为包含项目文件夹的文件夹。

运行以下命令:

dotnet new webapi -o TodoApi cd TodoApi dotnet add package Microsoft.EntityFrameworkCore.InMemory code -r ../TodoApi

当对话框询问是否要将所需资产添加到项目时,选择“是”。

前面的命令:

创建新的 web API 项目,并在 Visual Studio Code 中打开它。 添加下一部分中所需的 NuGet 包。

选择“文件”>“新建解决方案”>。

在版本 8.6 之前的 Visual Studio for Mac 中,依次选择“.NET Core”>“应用”>“API”>“下一步”。 在版本 8.6 或更高版本中,依次选择“Web 和控制台”>“应用”>“API”>“下一步”。

在“配置新的 ASP.NET Core Web API”对话框中,选择最新的 .NET Core 3.x 目标框架。 选择“下一步”。

输入“TodoApi”作为“项目名称”,然后选择“创建”。

访问 Mac 上的命令终端

首次访问 Mac 上的命令终端需要以下设置配置:

导航到“系统首选项”>“键盘”>“快捷方式”>“服务”。 在“文件和文件夹”下,验证是否选中了“文件夹中的新终端”。

上述说明以两种方式实现访问命令终端:从 Visual Studio 内访问或通过查找器访问 。

若要从 Visual Studio for Mac 访问命令终端,请执行以下操作: 右键单击项目名称。 导航到“工具”>“在终端中打开”。 若要通过查找器访问命令终端,请执行以下操作: 右键单击所需文件夹。 在列表底部,选择“文件夹中的新终端”。

在项目文件夹中打开命令终端并运行以下命令:

dotnet add package Microsoft.EntityFrameworkCore.InMemory

注意

有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。

测试 API

项目模板会创建 WeatherForecast API。 从浏览器调用 Get 方法以测试应用。

Visual Studio Visual Studio Code Visual Studio for Mac

按 Ctrl+F5 运行应用。 Visual Studio 启动浏览器并导航到 https://localhost:/weatherforecast,其中 是随机选择的端口号。

如果出现询问是否应信任 IIS Express 证书的对话框,则选择“是”。 在接下来出现的“安全警告”对话框中,选择“是”。

按 Ctrl+F5 运行应用。 在浏览器中,转到以下 URL:https://localhost:5001/weatherforecast。

选择“运行”>“开始调试”以启动应用。 Visual Studio for Mac 会启动浏览器并导航到 https://localhost:,其中 是随机选择的端口号。 将返回 HTTP 404(未找到)错误。 将 /weatherforecast 追加到 URL(将 URL 更改为 https://localhost:/weatherforecast)。

返回类似于以下项的 JSON:

[ { "date": "2019-07-16T19:04:05.7257911-06:00", "temperatureC": 52, "temperatureF": 125, "summary": "Mild" }, { "date": "2019-07-17T19:04:05.7258461-06:00", "temperatureC": 36, "temperatureF": 96, "summary": "Warm" }, { "date": "2019-07-18T19:04:05.7258467-06:00", "temperatureC": 39, "temperatureF": 102, "summary": "Cool" }, { "date": "2019-07-19T19:04:05.7258471-06:00", "temperatureC": 10, "temperatureF": 49, "summary": "Bracing" }, { "date": "2019-07-20T19:04:05.7258474-06:00", "temperatureC": -1, "temperatureF": 31, "summary": "Chilly" } ] 添加模型类

模型是一组表示应用管理的数据的类。 此应用的模型是单个 TodoItem 类。

Visual Studio Visual Studio Code Visual Studio for Mac

在“解决方案资源管理器”中,右键单击项目。 选择“添加”>“新建文件夹”。 将该文件夹命名为 Models注册一个免费试用帐户。

右键单击 Models 文件夹,然后选择“添加”>“类”。 将类命名为 TodoItem,然后选择“添加”。

将模板代码替换为以下代码:

添加名为 Models 的文件夹。

使用以下代码将 TodoItem 类添加到 Models 文件夹:

右键单击项目。 选择“添加”>“新建文件夹”。 将该文件夹命名为 Models注册一个免费试用帐户。

右键单击 Models 文件夹,然后选择“添加”>“新建文件”>“常规”>“空类”。

将类命名为“TodoItem”,然后单击“新建”。

将模板代码替换为以下代码:

public class TodoItem { public long Id { get; set; } public string Name { get; set; } public bool IsComplete { get; set; } }

Id 属性用作关系数据库中的唯一键。

模型类可位于项目的任意位置,但按照惯例会使用 Models 文件夹。

添加数据库上下文

数据库上下文是为数据模型协调 Entity Framework 功能的主类。 此类由 Microsoft.EntityFrameworkCore.DbContext 类派生而来。

Visual Studio Visual Studio Code / Visual Studio for Mac 添加 NuGet 包 在“工具”菜单中,选择“NuGet 包管理器”>“管理解决方案的 NuGet 包”。 选择“浏览”选项卡,然后在搜索框中输入“Microsoft.EntityFrameworkCore.InMemory” 。 在左窗格中选择“Microsoft.EntityFrameworkCore.InMemory”。 选中右窗格中的“项目”复选框,然后选择“安装”。

添加 TodoContext 数据库上下文 右键单击 Models 文件夹,然后选择“添加”>“类”。 将类命名为 TodoContext,然后单击“添加”。 将 TodoContext 类添加到 Models 文件夹。

输入以下代码:

using Microsoft.EntityFrameworkCore; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions options) : base(options) { } public DbSet TodoItems { get; set; } } } 注册数据库上下文

在 ASP.NET Core 中,服务(如数据库上下文)必须向依赖关系注入 (DI) 容器进行注册。 该容器向控制器提供服务。

使用以下突出显示的代码更新 Startup.cs:

// Unused usings removed using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.EntityFrameworkCore; using TodoApi.Models; namespace TodoApi { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddDbContext(opt => opt.UseInMemoryDatabase("TodoList")); services.AddControllers(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } }

前面的代码:

删除未使用的 using 声明。 将数据库上下文添加到 DI 容器。 指定数据库上下文将使用内存中数据库。 构建控制器 Visual Studio Visual Studio Code / Visual Studio for Mac

右键单击 Controllers 文件夹。

选择“添加”>“新建构建项”。

选择“其操作使用实体框架的 API 控制器”,然后选择“添加” 。

在“添加其操作使用实体框架的 API 控制器”对话框中:

在“模型类”中选择“TodoItem (TodoApi.Models)” 。 在“数据上下文类”中选择“TodoContext (TodoAPI.Models)” 。 选择“添加”。

运行以下命令:

dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design dotnet add package Microsoft.EntityFrameworkCore.Design dotnet tool install --global dotnet-aspnet-codegenerator dotnet tool update -g Dotnet-aspnet-codegenerator dotnet aspnet-codegenerator controller -name TodoItemsController -async -api -m TodoItem -dc TodoContext -outDir Controllers

前面的命令:

添加构建所需的 NuGet 包。 安装构建引擎 (dotnet-aspnet-codegenerator)。 构建 TodoItemsController。

注意

默认情况下,要安装的 .NET 二进制文件的体系结构表示当前运行的 OS 体系结构。 若要指定不同的 OS 体系结构,请参阅 dotnet tool install, --arch option。 有关详细信息,请参阅 GitHub 问题 dotnet/AspNetCore.Docs #29262。

生成的代码:

使用 [ApiController] 属性标记类。 此属性指示控制器响应 Web API 请求。 有关该属性启用的特定行为的信息,请参阅使用 ASP.NET Core 创建 Web API。 使用 DI 将数据库上下文 (TodoContext) 注入到控制器中。 数据库上下文将在控制器中的每个 CRUD 方法中使用。

ASP.NET Core 模板:

具有视图的控制器在路由模板中包含 [action]。 API 控制器不在路由模板中包含 [action]。

如果 [action] 标记不在路由模板中,则从路由中排除操作名称。 也就是说,不会在匹配的路由中使用操作的关联方法名称。

检查 PostTodoItem create 方法

替换 PostTodoItem 中的返回语句,以使用 nameof 运算符:

// POST: api/TodoItems [HttpPost] public async Task PostTodoItem(TodoItem todoItem) { _context.TodoItems.Add(todoItem); await _context.SaveChangesAsync(); //return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem); return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem); }

前面的代码是 HTTP POST 方法,如 [HttpPost] 属性所指示。 该方法从 HTTP 请求正文获取待办事项的值。

有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

CreatedAtAction 方法:

如果成功,则返回 HTTP 201 状态代码。 HTTP 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。 向响应添加位置标头。 Location 标头指定新建的待办事项的 URI。 有关详细信息,请参阅创建的 201。 引用 GetTodoItem 操作以创建 Location 标头的 URI。 C# nameof 关键字用于避免在 CreatedAtAction 调用中硬编码操作名称。 安装 Postman

本教程使用 Postman 测试 Web API。

安装 Postman 启动 Web 应用。 启动 Postman。 禁用“SSL 证书验证”: Postman for Windows:Postman for Windows“文件”>“设置”(“常规”选项卡),禁用“SSL 证书验证”。 Postman for macOS:Postman for Windows“Postman”>“设置”(“常规”选项卡),禁用“SSL 证书验证”。

警告

在测试控制器之后重新启用 SSL 证书验证。

通过 Postman 测试 PostTodoItem

创建新请求。

将 HTTP 方法设置为 POST。

将 URI 设置为 https://localhost:/api/todoitems。 例如 https://localhost:5001/api/todoitems。

选择“正文”选项卡。

选择“原始”单选按钮。

将类型设置为 JSON (application/json)。

在请求正文中,输入待办事项的 JSON:

{ "name":"walk dog", "isComplete":true }

选择Send。

使用 Postman 测试位置标头 URI

在Headers 窗格中选择Response 选项卡。

复制Location 标头值:

将 HTTP 方法设置为 GET。

将 URI 设置为 https://localhost:/api/todoitems/1。 例如 https://localhost:5001/api/todoitems/1。

选择Send。

检查 GET 方法

这些方法实现两个 GET 终结点:

GET /api/todoitems GET /api/todoitems/{id}

通过从浏览器或 Postman 调用两个终结点来测试应用。 例如:

https://localhost:5001/api/todoitems https://localhost:5001/api/todoitems/1

对 GetTodoItems 的调用生成类似于以下项的响应:

[ { "id": 1, "name": "Item1", "isComplete": false } ] 使用 Postman 测试 Get 创建新请求。 将 HTTP 方法设置为“GET”。 将请求 URI 设置为 https://localhost:/api/todoitems。 例如 https://localhost:5001/api/todoitems。 在 Postman 中设置Two pane view 。 选择Send。

此应用使用内存中数据库。 如果应用已停止并启动,则前面的 GET 请求将不会返回任何数据。 如果未返回任何数据,将数据 POST 到应用。

路由和 URL 路径

[HttpGet] 特性表示对 HTTP GET 请求进行响应的方法。 每个方法的 URL 路径构造如下所示:

在控制器的 Route 属性中以模板字符串开头:

[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase { private readonly TodoContext _context; public TodoItemsController(TodoContext context) { _context = context; }

将 [controller] 替换为控制器的名称,按照惯例,在控制器类名称中去掉“Controller”后缀。 对于此示例,控制器类名称为“TodoItems”控制器,因此控制器名称为“TodoItems”。 ASP.NET Core 路由不区分大小写。

如果 [HttpGet] 属性具有路由模板(例如 [HttpGet("products")]),则将它追加到路径。 此示例不使用模板。 有关详细信息,请参阅使用 Http [Verb] 特性的特性路由。

在下面的 GetTodoItem 方法中,"{id}" 是待办事项的唯一标识符的占位符变量。 调用 GetTodoItem 时,URL 中 "{id}" 的值会在 id 参数中提供给方法。

// GET: api/TodoItems/5 [HttpGet("{id}")] public async Task GetTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } return todoItem; } 返回值

GetTodoItems 和 GetTodoItem 方法的返回类型是 ActionResult 类型。 ASP.NET Core 自动将对象序列化为 JSON,并将 JSON 写入响应消息的正文中。 在假设没有未经处理的异常的情况下,此返回类型的响应代码为 200。 未经处理的异常将转换为 5xx 错误。

ActionResult 返回类型可以表示大范围的 HTTP 状态代码。 例如,GetTodoItem 可以返回两个不同的状态值:

如果没有任何项与请求的 ID 匹配,则该方法将返回 404 NotFound 错误代码。 否则,此方法将返回具有 JSON 响应正文的 200。 返回 item 则产生 HTTP 200 响应。 PutTodoItem 方法

检查 PutTodoItem 方法:

// PUT: api/TodoItems/5 [HttpPut("{id}")] public async Task PutTodoItem(long id, TodoItem todoItem) { if (id != todoItem.Id) { return BadRequest(); } _context.Entry(todoItem).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!TodoItemExists(id)) { return NotFound(); } else { throw; } } return NoContent(); }

PutTodoItem 与 PostTodoItem 类似,但是使用的是 HTTP PUT。 响应是 204(无内容)。 根据 HTTP 规范,PUT 请求需要客户端发送整个更新的实体,而不仅仅是更改。 若要支持部分更新,请使用 HTTP PATCH。

如果在调用 PutTodoItem 时出错,请调用 GET 以确保数据库中有项目。

测试 PutTodoItem 方法

本示例使用内存内、数据库,每次启动应用时都必须对其进行初始化。 在进行 PUT 调用之前,数据库中必须有一个项。 调用 GET,以确保在调用 PUT 之前数据库中存在项。

更新 ID 为 1 的待办事项并将其名称设置为“feed fish”:

{ "id":1, "name":"feed fish", "isComplete":true }

下图显示 Postman 更新:

DeleteTodoItem 方法

检查 DeleteTodoItem 方法:

// DELETE: api/TodoItems/5 [HttpDelete("{id}")] public async Task DeleteTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } _context.TodoItems.Remove(todoItem); await _context.SaveChangesAsync(); return todoItem; } 测试 DeleteTodoItem 方法

使用 Postman 删除待办事项:

将方法设置为 DELETE。 设置要删除的对象的 URI,例如 https://localhost:5001/api/todoitems/1。 选择Send。

防止过度发布

目前,示例应用公开了整个 TodoItem 对象。 生产应用通常使用模型的子集来限制输入和返回的数据。 这背后有多种原因,但安全性是主要原因。 模型的子集通常称为数据传输对象 (DTO)、输入模型或视图模型。 本文使用的是 DTO。

DTO 可用于:

防止过度发布。 隐藏客户端不应查看的属性。 省略一些属性以缩减有效负载大小。 平展包含嵌套对象的对象图。 对客户端而言,平展的对象图可能更方便。

若要演示 DTO 方法,请更新 TodoItem 类,使其包含机密字段:

public class TodoItem { public long Id { get; set; } public string Name { get; set; } public bool IsComplete { get; set; } public string Secret { get; set; } }

此应用需要隐藏机密字段,但管理应用可以选择公开它。

确保可以发布和获取机密字段。

创建 DTO 模型:

public class TodoItemDTO { public long Id { get; set; } public string Name { get; set; } public bool IsComplete { get; set; } }

更新 TodoItemsController 以使用 TodoItemDTO:

[HttpGet] public async Task GetTodoItems() { return await _context.TodoItems .Select(x => ItemToDTO(x)) .ToListAsync(); } [HttpGet("{id}")] public async Task GetTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } return ItemToDTO(todoItem); } [HttpPut("{id}")] public async Task UpdateTodoItem(long id, TodoItemDTO todoItemDTO) { if (id != todoItemDTO.Id) { return BadRequest(); } var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } todoItem.Name = todoItemDTO.Name; todoItem.IsComplete = todoItemDTO.IsComplete; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) when (!TodoItemExists(id)) { return NotFound(); } return NoContent(); } [HttpPost] public async Task CreateTodoItem(TodoItemDTO todoItemDTO) { var todoItem = new TodoItem { IsComplete = todoItemDTO.IsComplete, Name = todoItemDTO.Name }; _context.TodoItems.Add(todoItem); await _context.SaveChangesAsync(); return CreatedAtAction( nameof(GetTodoItem), new { id = todoItem.Id }, ItemToDTO(todoItem)); } [HttpDelete("{id}")] public async Task DeleteTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { return NotFound(); } _context.TodoItems.Remove(todoItem); await _context.SaveChangesAsync(); return NoContent(); } private bool TodoItemExists(long id) => _context.TodoItems.Any(e => e.Id == id); private static TodoItemDTO ItemToDTO(TodoItem todoItem) => new TodoItemDTO { Id = todoItem.Id, Name = todoItem.Name, IsComplete = todoItem.IsComplete }; }

确保无法发布或获取机密字段。

使用 JavaScript 调用 Web API

请参阅教程:使用 JavaScript 调用 ASP.NET Core Web API。

向 Web API 添加身份验证支持

ASP.NET Core Identity 将用户界面 (UI) 登录功能添加到 ASP.NET Core Web 应用。 若要保护 Web API 和 SPA,请使用以下项之一:

Microsoft Entra ID Azure Active Directory B2C (Azure AD B2C) Duende Identity Server

Duende Identity Server 是适用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 框架。 Duende Identity Server 支持以下安全功能:

身份验证即服务 (AaaS) 跨多个应用程序类型的单一登录/注销 (SSO) API 的访问控制 Federation Gateway

重要事项

Duende Software 可能会要求你为 Duende Identity Server 的生产使用支付许可证费用。 有关详细信息,请参阅从 ASP.NET Core 5.0 迁移到 6.0。

有关详细信息,请参阅 Duende Identity Server 文档(Duende Software 网站)。

发布到 Azure

有关部署到 Azure 的信息,请参阅快速入门:部署 ASP.NET Web 应用。

其他资源

查看或下载本教程的示例代码。 请参阅如何下载。

有关更多信息,请参见以下资源:

使用 ASP.NET Core 创建 Web API 教程:使用 ASP.NET Core 创建最小 API 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档 RazorASP.NET Core 中的 Pages 和 Entity Framework Core - 第 1 个教程(共 8 个) 在 ASP.NET Core 中路由到控制器操作 ASP.NET Core Web API 中控制器操作的返回类型 将 ASP.NET Core 应用部署到 Azure 应用服务 托管和部署 ASP.NET Core 使用 ASP.NET Core 创建 Web API


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有